home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 8
/
QRZ Ham Radio Callsign Database - Volume 8.iso
/
pc
/
files
/
dsp
/
56000tar.z
/
56000tar
/
56000
/
speech
/
adpcm.asm
next >
Wrap
Assembly Source File
|
1991-11-26
|
121KB
|
3,107 lines
;
; This program originally available on the Motorola DSP bulletin board.
; It is provided under a DISCLAMER OF WARRANTY available from
; Motorola DSP Operation, 6501 Wm. Cannon Drive W., Austin, Tx., 78735.
;
;**************************************************************************
;
; ADPCM.ASM Full-Duplex 32-kbit/s CCITT ADPCM Algorithm
;
; Version 1.0 - 1/27/89
;
; This program implements the algorithm defined in CCITT Recommendation
; G.721: "32 kbit/s Adaptive Differential Pulse Code Modulation" dated
; August 1986. This version passes all of the mu-law and A-law test
; sequences as defined in Appendix II of Recommendation G.721.
;
; Please refer to the file ADPCM.HLP for further information about
; this program.
;
;**************************************************************************
OPT CC,CEX
START EQU $0040
ORG X:$0000
;******************** Encoder variables ***********************************
; I = siii 0000 | 0000 0000 | 0000 0000 (ADPCM format)
I_T DS 1 ;ADPCM codeword
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
DQ_T DS 1 ;Quantized difference signal
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
Y_T DS 1 ;Quantizer scale factor
; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
AP_T DS 1 ;Unlimited speed control parameter
; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM)
AL_T DS 1 ;Limited speed control parameter
;******************** Decoder variables ***********************************
I_R DS 1 ;ADPCM codeword
DQ_R DS 1 ;Quantized difference signal
Y_R DS 1 ;Quantizer scale factor
AP_R DS 1 ;Unlimited speed control parameter
AL_R DS 1 ;Limited speed control parameter
; SP = psss qqqq | 0000 0000 | 0000 0000 (PCM log format)
SP_R DS 1 ;PCM reconstructed signal
;******************** Temporary variables *********************************
; IMAG = 0iii. 0000 | 0000 0000 | 0000 0000
IMAG DS 1 ;|I|
; PKS1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
PKS1 DS 1 ;XOR of PK0 & PK1
; PKS2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
PKS2 DS 1 ;XOR of PK0 & PK2
DATAPTR_T DS 1 ;Transmit data buffer pointer
DATAPTR_R DS 1 ;Receive data buffer pointer
;******************** Table for quantizing DLN ****************************
; Used in QUAN routine
QUANTAB DS 8
;******************** Table for unquantizing I ****************************
; Used in RECONST
IQUANTAB DS 8
;******************** W(I) lookup table ***********************************
; Used in FUNCTW routine
WIBASE DS 8
;******************** Table used in COMPRESS ******************************
TAB DS 8
;******************** Constants used by FMULT *****************************
CONST DS 6
;******************** Encoder data buffer *********************************
; DQn (11FL) stored separately as exponent, mantissa, and sign
; DQnEXP = 0000 0000 | 0000 0000 | 0000 eeee
; DQnMANT = 01mm mmm0 | 0000 0000 | 0000 0000
; DQnS = sXXX XXXX | XXXX XXXX | 0000 0000
; SRn in same format
DATA_T DSM 24 ;24 word modulo buffer for data,
; R2 is used as pointer, DATAPTR_T
; points to start of buffer (DQ1EXP)
; at beginning of cycle
;DQ1EXP,DQ1MANT,DQ1S
;DQ2EXP,DQ2MANT,DQ2S
;DQ3EXP,DQ3MANT,DQ3S
;DQ4EXP,DQ4MANT,DQ4S
;DQ5EXP,DQ5MANT,DQ5S
;DQ6EXP,DQ6MANT,DQ6S
;SR1EXP,SR1MANT,SR1S
;SR2EXP,SR2MANT,SR2S
;******************** Encoder partial product buffer **********************
; WBn = siii iiii | iiii iii.f | 0000 0000 (16TC)
; WAn in same format
PP_T DSM 8 ;8 word modulo buffer for partial
; products, R1 is used as pointer
;WB1
;WB2
;WB3
;WB4
;WB5
;WB6
;WA1
;WA2
;******************** Decoder data buffer *********************************
DATA_R DSM 24 ;24 word modulo buffer for data
; (same format as DATA_T)
;******************** Decoder partial product buffer **********************
PP_R DSM 8 ;8 word modulo buffer for partial products
; (same format as PP_T)
ORG Y:$0000
;******************** Encoder variables ***********************************
; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC)
SE_T DS 1 ;Signal estimate
; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC)
SEZ_T DS 1 ;Partial signal estimate
; SR = siii iiii | iiii iiii. | 0000 0000 (16TC)
SR_T DS 1 ;Reconstructed signal
; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
PK0_T DS 1 ;Sign of DQ + SEZ
; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
PK1_T DS 1 ;Delayed sign of DQ + SEZ
; PK2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
PK2_T DS 1 ;Delayed sign of DQ + SEZ
; DMS = 0iii. ffff | ffff f000 | 0000 0000 (12SM)
DMS_T DS 1 ;Short term average of F(I)
; DML = 0iii. ffff | ffff fff0 | 0000 0000 (14SM)
DML_T DS 1 ;Long term average of F(I)
; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC)
TDP_T DS 1 ;Tone detect
; TD = i000 0000 | 0000 0000 | 0000 0000 (1TC)
TD_T DS 1 ;Delayed tone detect
; YU = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
YU_T DS 1 ;Fast quantizer scale factor
; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
YL_T DS 1 ;Slow quantizer scale factor
; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC)
SIGPK_T DS 1 ;Sgn[p(k)] flag
; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC)
A2P_T DS 1 ;Second order predictor coef
; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
TR_T DS 1 ;Transition detect
;******************** Decoder variables ***********************************
SE_R DS 1 ;Signal estimate
SEZ_R DS 1 ;Partial signal estimate
SR_R DS 1 ;Reconstructed signal
PK0_R DS 1 ;Sign of DQ + SEZ
PK1_R DS 1 ;Delayed sign of DQ + SEZ
PK2_R DS 1 ;Delayed sign of DQ + SEZ
DMS_R DS 1 ;Short term average of F(I)
DML_R DS 1 ;Long term average of F(I)
TDP_R DS 1 ;Tone detect
TD_R DS 1 ;Delayed tone detect
YU_R DS 1 ;Fast quantizer scale factor
YL_R DS 1 ;Slow quantizer scale factor
SIGPK_R DS 1 ;Sgn[p(k)] flag
A2P_R DS 1 ;Second order predictor coef
TR_R DS 1 ;Transition detect
;******************** Temporary variables *********************************
LAW DS 1 ;Select A-law or mu-law
DQMAG DS 1 ;|DQ|
;******************** Shift constant lookup table *************************
; Shift constants used for doing left or right shifts by multiplying by a
; power of 2. For right shift, some routines use R5 as a base and N5 as
; and offset for lookup of shift constant.
RSHFT DS 24
LSHFT
;******************** Misc. constants *************************************
CONST1 DS 3
CONST4 DS 4
CONST8 DS 9
CONST17 DS 16
;******************** Encoder coef. buffer ********************************
; Bn = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; An in same format
COEF_T DSM 8 ;8 word modulo buffer for coefs.,
; R6 is used as pointer
;B1
;B2
;B3
;B4
;B5
;B6
;A1
;A2
;******************** Decoder coef. buffer ********************************
COEF_R DSM 8 ;8 locations for coef. queue
; (same format as COEF_T)
PAGE
ORG P:$0000
JMP START
ORG P:START
CLR A
MOVEC #$06,OMR ;Enable internal ROM tables
MOVEP A,X:$FFFE ;Set BCR for 0 wait states
JSR INIT
;**************************************************************************
;
; Encoder
;
;**************************************************************************
ENCODE MOVE #PP_T,R1 ;Set partial product ptr to WB1
MOVE X:DATAPTR_T,R2 ;Set data pointer to DQ1EXP
MOVE #COEF_T,R6 ;Set coef pointer to B1
MOVE #CONST1,R7 ;Set pointer to misc constants
;**************************************************************************
; FMULT
;
; Multiply predictor coefficients with corresponding
; quantized difference signal or reconstructed signal
;
; Data (DQn or SRn) is stored in 11FL format (separate),
; & coefficient (Bn or An) is stored in 16TC format.
;
; Computes [An(k-1) * SR(k-n)] or [Bn(k-1) * DQ(k-n)]
;
; Flow Description:
; 1. Convert 16TC An to 13SM AnMAG
; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT)
; 3. Add SRnEXP to AnEXP to get WAnEXP (5-bits)
; 4. Multiply SRnMANT with AnMANT, add '48', and truncate
; to 8-bits to get WAnMANT
; 5. Convert 13FL (WAnEXP & WAnMANT) to 15SM WAnMAG
; 6. XOR AnS with SRnS to find WAnS
; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn
;
; Input:
; SRn = (11FL)
; SRnEXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee
; SRnMANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000
; SRnS = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000
; (DQ in same format as SR)
;
; An = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; (Bn in same format as An)
;
; Output:
; WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC)
; (WBn in same format as WAn)
;
;**************************************************************************
MOVE #CONST,R0 ;Set pointer to FMULT constants
MOVE #0,Y1
DO #8,ACCUM_T ;Execute mult 8 times
; 1. Convert 16TC An to 13SM AnMAG
MOVE X:(R0)+,X1 Y:(R6),A ;Get An and mask KF1
AND X1,A X:(R0)+,X1 ;Truncate An to 13 bits (An>>2),
; get mask KF2
ABS A #$000D,R4 ;Find AnMAG, load
; exponent bias (13) into R4
AND X1,A #<$7E,X1 ;Truncate any ovrflw, get mask
; A1 = 0i.ff ffff | ffff ff00 | 0000 0000 (A2=A0=0)
; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT)
JNE <NORMAN_T ;Test AnMAG
MOVE #<$40,A ;If AnMAG=0, set AnMANT=1<<5,
MOVE #0,R4 ; and AnEXP=0
JMP <CONTIN_T
NORMAN_T NORM R4,A ;If AnMAG!=0 do NORM iteration
NORM R4,A ; 12 times to find MSB
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
; A1 = 01?? ???? | ???? ??00 | 0000 0000 = AnMANT
; R4 = 0000 0000 | 0000 eeee = AnEXP
CONTIN_T AND X1,A R4,B ;Truncate AnMANT to 6 bits,
; move AnEXP to B
; A1 = 01mm mmm0 | 0000 0000 | 0000 0000 (A2=A0=0)
; B1 = 0000 0000 | 0000 0000 | 0000 eeee (B2=B0=0)
; 3. Add SRnEXP to AnEXP to get WAnEXP (5-bits)
MOVE X:(R2)+,X1 A,Y0 ;Get SRnEXP
ADD X1,B X:(R2)+,X1 ;Find WAnEXP=SRnEXP+AnEXP,
; get SRnMANT
; B1 = 0000 0000 | 0000 0000 | 000e eeee (B2=B0=0)
; 4. Multiply SRnMANT with AnMANT, add '48', and truncate
; to 8-bits to get WAnMANT
; Y0 = 01mm mmm0 | 0000 0000 | 0000 0000
; X1 = 01mm mmm0 | 0000 0000 | 0000 0000
MPY Y0,X1,A X:(R0)+,X0 ;Find WAnMANT, get '48' (KF3)
; A1 = 0mmm mmmm | mmmm m000 | 0000 0000 (A2=A0=0)
; X0 = 0000 0001 | 1000 0000 | 0000 0000 = '48'
ADD X0,A X:(R0)+,X0 ;Add '48' to WAnMANT, get mask KF4
AND X0,A X:(R0)+,X0 ;Truncate WAnMANT to 8 bits,
; get '26' (KF5)
; A1 = 0mmm mmmm | m000 0000 | 0000 0000 (A2=A0=0)
; 5. Convert 13FL (WAnEXP & WAnMANT) to 15SM WAnMAG
; X0 = 0000 0000 | 0000 0000 | 0001 1010 = '26'
; B1 = 0000 0000 | 0000 0000 | 000e eeee (B2=B0=0)
SUB X0,B X:(R0)+,X0 ;Find shift offset (WAnEXP-26),
; get mask KF6
JEQ <TRUNC_T ;If offset=26 no shift
JMI <RIGHT_T ;If offset<26 do right shift
;Else offset>26, do left shift
REP B1 ;Offset>26, shift WAnMANT
LSL A ; left up to 4 times
JMP <TRUNC_T
RIGHT_T ABS B #>$0F,Y0 ;Find |offset|, get '15'
CMP Y0,B B1,N5 ;Compare |offset| to '15',
; load offset for shift
TGE Y1,A ;If |offset|>=15 WAnMAG=0
MOVE A1,X1 ;Move WAnMANT for shift
MOVE Y:(R5+N5),Y0 ;Lookup shift constant
MPY Y0,X1,A ;Shift WAnMANT right up to 14 times
; A1 = ?mmm mmmm | mmmm mmmm | ???? ???? (A2=A0=0)
TRUNC_T AND X0,A X:(R2)+,X1 Y:(R6)+,B ;Truncate WAnMAG to 15 bits,
; get SRnS & AnS
; A1 = 0iii iiii | iiii iii.f | 0000 0000 (A2=A0=0)
NEG A A1,X0 ;Find -WAnMAG, save WAnMAG
; 6. XOR AnS with SRnS to find WAnS
; B1 = sXXX XXXX | XXXX XXXX | 0000 0000 (B2=sign ext, B0=0)
; X1 = sXXX XXXX | XXXX XXXX | 0000 0000
EOR X1,B #CONST,R0 ;Find WAnS (in MSB of B),
; update pointer to constants
; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn
TPL X0,A ;If WAnS=0 use WAnMAG, else use -WAnMAG
; A1 = siii iiii | iiii iii.f | 0000 0000 (A2=sign ext, A0=0)
MOVE A1,X:(R1)+ ;Save WAn
;**************************************************************************
; ACCUM
;
; Add predictor outputs to form the partial signal estimate
; and the signal estimate
;
; SEZ(k) = [B1(k-1) * DQ(k-1)] + ... + [B6(k-1) * DQ(k-6)]
; = WB1 + WB2 + ... + WB6
;
; SE(k) = SEZ(k) + [A1(k-1) * SR(k-1)] + [A2(k-1) * SR(k-2)]
; = SEZ + WA1 + WA2
;
; Inputs:
; WBn & WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC)
;
; Outputs:
; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC)
; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
;**************************************************************************
ACCUM_T MOVE X:(R1)+,A ;Get WB1
MOVE X:(R1)+,X0 ;Get WB2
ADD X0,A X:(R1)+,X0 ;Accumulate WB1&WB2, get WB3
ADD X0,A X:(R1)+,X0 ;Accumulate WB3, get WB4
ADD X0,A X:(R1)+,X0 ;Accumulate WB4, get WB5
ADD X0,A X:(R1)+,X0 ;Accumulate WB5, get WB6
ADD X0,A X:(R1)+,X0 ;Accumulate WB6 to get SEZI, get WA1
TFR A,B Y:(R7)+,X1 ;Copy SEZI, get mask K1
AND X1,B X:AP_T,Y0 ;Truncate SEZI, get AP
ADD X0,A X:(R1)+,X0 ;Accumulate WA1, get WA2
ADD X0,A B1,Y:SEZ_T ;Accumulate WA2 to get SEI, save SEZ
AND X1,A #<$20,X0 ;Truncate SEI, get '1'
TFR Y0,A A1,Y:SE_T ;Move AP, save SE
;**************************************************************************
; LIMA
;
; Limit speed control parameter
;
; AL(k) = 1 if AP(k-1) > 1
; = AP(k-1) if AP(k-1) <= 1
;
; Inputs:
; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
; Outputs:
; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM)
;
;**************************************************************************
CMP X0,A Y:YL_T,B ;Test AP, get YL
TGT X0,A ;If AP>'1' set AL='1'
LSL A #<$7F,X0 ;Shift to align radix pt., get mask
AND X0,A Y:(R7)+,X0 ;Truncate AL (AP>>2), get mask K2
;**************************************************************************
; MIX
;
; Form linear combination of fast and slow quantizer
; scale factors
;
; Y(k) = AL(k) * YU(k-1) + [1 - AL(k)] * YL(k-1)
;
; Inputs:
; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM)
; YU = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Outputs:
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
;**************************************************************************
AND X0,B A,X0 Y:YU_T,A ;Truncate YL (YL>>6), get YU
SUB B,A B,Y1 X0,X:AL_T ;Find DIF=YU-YL, save YL, get AL
ABS A A,B ;Find DIFM=|DIF|, save DIFS
MOVE A1,Y0
MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFM*AL, get mask K3
AND X0,A ;Truncate to find PRODM=(DIFM*AL)>>6
NEG A A1,X0 ;Find -PRODM, save PRODM
TST B ;Check DIFS
TPL X0,A ;If DIFS=0 PROD=PRODM,
; else PROD=-PRODM
ASL A Y1,B ;Line up radix point
ADD Y1,A ;Find Y=PROD+(YL>>6)
MOVE A,X:Y_T ;Save Y
;**************************************************************************
;
; Input PCM data (S) here. For simulation purposes the Input
; Word from File subroutine on the 56001 ADS board is used.
;
;**************************************************************************
MOVE #1,X0 ;Input PCM word (S)
JSR $E002
;**************************************************************************
; EXPAND
;
; Convert A-law or mu-law PCM to uniform PCM (according to
; Recommendation G.711). For further details see Motorola
; application bulletin "Logarithmic/Linear Conversion
; Routines for DSP56000/1".
;
; Input:
; S = psss qqqq | 0000 0000 | 0000 0000 (PCM log format)
;
; Output:
; SL = siii iiii | iiii ii.00 | 0000 0000 (14TC)
;
;**************************************************************************
MOVE A,X0 Y:(R7)+,Y1 ;Get shift constant K4
MPY X0,Y1,A Y:(R7)+,X1 ;Shift S to 8 lsb's of A1, get K5
AND X1,A Y:SE_T,B ;Mask off sign of S, get SE
ASR B A1,N3 ;sign extend SE, load |S| as offset
CMPM Y1,A ;Check sign of S
MOVE X:(R3+N3),A ;Lookup |SL| from ROM table
JGE <SUBTA_T ;If S=0, SL=|SL|
NEG A ;If S=1, SL=-|SL|
;**************************************************************************
; SUBTA
;
; Compute difference signal by subtracting signal estimate
; from input signal
;
; D(k) = SL(k) - SE(k)
;
; Inputs:
; SL = siii iiii | iiii ii.00 | 0000 0000 (14TC)
; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
; Output:
; D = siii iiii | iiii iiii. | 0000 0000 (16TC)
;**************************************************************************
SUBTA_T ASR A Y:(R7)+,X1 ;Sign extend SL, get mask K6
ASR A #$000E,R0 ;Sign extend SE again, get exp bias (14)
SUB B,A X:Y_T,B ;Find D=SL-SE, get Y
;**************************************************************************
; LOG
;
; Convert difference signal from the linear to the log
; domain
;
; Input:
; D = siii iiii | iiii iiii. | 0000 0000 (16TC)
;
; Outputs:
; DL = 0iii i.fff | ffff 0000 | 0000 0000 (11SM)
; DS = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
;**************************************************************************
ABS A A,Y1 ;Find DQM=|D|, save DS to Y1
JNE <NORMEXP_T ;Check for DQM=0
CLR A (R7)+ ;If DQM=0 set DL=0,
MOVE Y:(R7),X0 ; get mask K8,
JMP <SUBTB_T ; and continue
NORMEXP_T NORM R0,A ;If DQM!=0, do norm iteration
NORM R0,A ; 14 times to find MSB of DQM
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
; A1 = 01?? ???? | ???? ???? | 0000 0000 = normalized DQM (A2=A0=0)
; R0 = 0000 0000 | 0000 eeee = exponent of normalized DQM
; Get rid of leading "1" in normalized DQM
; Truncate mantissa to 7 bits and combine with exponent
AND X1,A Y:LSHFT-19,X0 ;Truncate MANT, get EXP shift
; A1 = 00mm mmmm | m000 0000 | 0000 0000 (A2=A0=0)
MOVE R0,X1 ;Move EXP to X1
MPY X0,X1,A A,X1 Y:(R7)+,Y0 ;Shift EXP<<19, save MANT to X1,
; get mask K7
MOVE A0,A ;Move EXP to A1
; A1 = 0eee e000 | 0000 0000 | 0000 0000 (A2=A0=0)
MAC Y0,X1,A Y:(R7),X0 ;Shift MANT>>3 & combine with EXP,
; get mask K8
; A1 = 0eee e.mmm | mmmm 0000 | 0000 0000 (A2=A0=0)
; = 0iii i.fff | ffff 0000 | 0000 0000 (A2=A0=0)
;**************************************************************************
; SUBTB
;
; Scale log version of difference signal by subtracting
; scale factor
;
; DLN = DL - Y
;
; Inputs:
; DL = 0iii i.fff | ffff 0000 | 0000 0000 (11SM)
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Output:
; DLN = siii i.fff | ffff 0000 | 0000 0000 (12TC)
;
;**************************************************************************
SUBTB_T AND X0,B #QUANTAB,R0 ;Truncate Y to 11 bits (Y>>2),
; get quantization table base
SUB B,A #>QUANTAB+2,X1 ;Find DLN=DL-Y,
; get offset for quan. conversion
;**************************************************************************
; QUAN
;
; Quantize difference signal in log domain
;
; log2|D(k)| - Y(k) | |I(k)|
; ------------------+--------
; [3.12, + inf) | 7
; [2.72, 3.12) | 6
; [2.34, 2.72) | 5
; [1.91, 2.34) | 4
; [1.38, 1.91) | 3
; [0.62, 1.38) | 2
; [-0.98, 0.62) | 1
; (- inf, -0.98) | 0
;
; Inputs:
; DLN = siii i.fff | ffff 0000 | 0000 0000 (12TC)
; DS = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
; Output:
; I = siii 0000 | 0000 0000 | 0000 0000 (ADPCM format)
;
;**************************************************************************
MOVE X:(R0)+,X0 ;Get quan table value
TSTDLN_T CMP X0,A X:(R0)+,X0 ;Compare to DLN
JGE <TSTDLN_T ;If value<DLN try next range
MOVE R0,A ;When range found...
; subtract pointer from
SUB X1,A Y:LSHFT-20,X0 ; base to get IMAG=|I|
; A1 = 0000 0000 | 0000 0000 | 0000 0iii (A2=A0=0)
MOVE A1,X1
MPY X0,X1,A Y1,B ;Shift IMAG <<20, result is
; in A0, move DS (from LOG) into B
MOVE A0,A
; A1 = 0iii 0000 | 0000 0000 | 0000 0000 (A2=A0=0)
MOVE A1,X:IMAG ;Save IMAG
TST A #<$F0,X0 ;Check IMAG, get invert mask
JEQ <INVERT_T ;If IMAG=0 invert bits
TST B ;If IMAG!=0, check DS
JPL <IOUT_T ;If DS=1 don't invert IMAG
INVERT_T EOR X0,A ;If DS=0 or IMAG=0,
; invert IMAG
IOUT_T MOVE A1,A ;Adjust sign extension
;**************************************************************************
;
; Output ADPCM data (I) here. For simulation purposes the Output
; Word to File subroutine on the 56001 ADS board is used.
;
;**************************************************************************
MOVE #1,X0 ;Output ADPCM word (I)
JSR $E004
;**************************************************************************
; RECONST
;
; Reconstruct quantized difference signal in the log domain
;
; |I(k)| | log2|DQ(k)| - Y(k)
; --------+-------------------
; 7 | 3.32
; 6 | 2.91
; 5 | 2.52
; 4 | 2.13
; 3 | 1.66
; 2 | 1.05
; 1 | 0.031
; 0 | - inf
;
; Inputs:
; I = iiii 0000 | 0000 0000 | 0000 0000 (ADPCM format)
;
; Output:
; DQLN = siii i.fff | ffff 0000 | 0000 0000 (12TC)
; DQS = sXXX 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE A,Y1 A,X:I_T ;Save DQS (sign of I) to Y1
MOVE #IQUANTAB,R4 ;Set lookup table base
; X1 = 0000 0000 | 0000 0000 | 0000 0iii = |I| (from QUAN)
MOVE X1,N4 ;Load |I| as offset
MOVE X:Y_T,B ; into IQUAN table, get Y
MOVE X:(R4+N4),A ;Lookup DQLN
;**************************************************************************
; ADDA
;
; Add scale factor to log version of quantized difference
; signal
;
; DQL = DQLN + Y
;
; Inputs:
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
; DQLN = siii i.fff | ffff 0000 | 0000 0000 (12TC)
;
; Output:
; DQL = siii i.fff | ffff 0000 | 0000 0000 (12TC)
;
;**************************************************************************
MOVE Y:(R7)+,Y0 ;Get mask K8 for ADDA
AND Y0,B Y:(R7)+,X0 ;Truncate Y to 11 bits (Y<<2),
; get mask K9
ADD B,A #<$08,X1 ;Find DQL=DQLN+(Y<<2), get '1'
;**************************************************************************
; ANTILOG
;
; Convert quantized difference signal from log to linear
; domain
;
; Input:
; DQL = siii i.fff | ffff 0000 | 0000 0000 (12TC)
; DQS = sXXX 0000 | 0000 0000 | 0000 0000 (1TC)
;
; Outputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
;
;**************************************************************************
JPL <CONVLOG_T ;If DQL>=0 (DS=0) convert DQL,
; else DQL<0 (DS=1), set |DQ|=0
TFR Y1,A #<$80,X0 ;Get DQS (MSB of I), get mask
AND X0,A #0,B ;Mask off DQS, set |DQ|=0
; A1 = s000 0000 | 0000 0000 | 0000 0000 (A2=sign ext, A0=0)
MOVE B1,Y:DQMAG ;Save DQMAG=|DQ|
MOVE (R7)+ ;Adjust constant pointer
MOVE (R7)+
JMP <SAVEDQ_T
CONVLOG_T AND X0,A A,B ;Find fractional part (DMN),
; save DS
; A1 = 0000 0.fff | ffff 0000 | 0000 0000 (A2=A0=0)
OR X1,A #<$78,X0 ;Add implied '1' to DMN to
; find DQT, get integer mask
; A1 = 0000 1.fff | ffff 0000 | 0000 0000 (A2=A0=0)
AND X0,B Y:RSHFT+19,Y0 ;Find integer part (DEX),
; get shift constant
; B1 = 0iii i.000 | 0000 0000 | 0000 0000 (B2=B0=0)
MOVE B1,X0
MPY X0,Y0,B Y:(R7)+,X0 ;Shift DEX>>19, get '10' (K10)
; A1 = 0000 1.fff | ffff 0000 | 0000 0000 (A2=A0=0)
; B1 = 0000 0000 | 0000 0000 | 0000 iiii. (B2=B0=0)
SUB X0,B Y:(R7)+,X0 ;Find DQT shift=DEX-'10',
; get mask K11
JEQ <TRUNCDQM_T ;If DEX=10, no shift
JLT <SHFRDQ_T ;If DEX<10, shift right
REP B1 ;Else shift DQT left
LSL A ; up to 4 times
JMP <TRUNCDQM_T
SHFRDQ_T NEG B ;Find 10-DEX
MOVE B1,N5 ;Use 10-DEX for shift lookup
MOVE A1,Y0
MOVE Y:(R5+N5),X1 ;Lookup shift constant
MPY X1,Y0,A ;Shift DQT right up to 9 times
TRUNCDQM_T AND X0,A #<$80,B ;Truncate to find DQMAG=|DQ|,
; get sign mask
; A1 = 0iii iiii | iiii iii.0 | 0000 0000 (A2=A0=0)
AND Y1,B A1,Y:DQMAG ;Mask off DQS, save DQMAG
; B1 = s000 0000 | 0000 0000 | 0000 0000 (B2=?, B0=0)
MOVE B1,X0
OR X0,A ;Add DQS to DQMAG to get DQ
; A1 = siii iiii | iiii iii.0 | 0000 0000 (A2=?, A0=0)
SAVEDQ_T MOVE A1,X:DQ_T ;Save DQ
;**************************************************************************
; TRANS
;
; Transition detector
;
; TR(k) = 1 if TD(k)=1 and |DQ(k)|> 24 x 2**(YL(k))
; 0 otherwise
;
; Inputs:
; TD = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
;
; Output:
; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE Y:TD_T,A ;Get TD
TST A #0,A ;Check TD, set TR=0
JEQ <SAVETR_T ;If TD=0 save TR=0
; else test DQ and YL
MOVE Y:YL_T,A ;Get YL
TFR A,B Y:(R7)+,X0 ;Save YL, get mask K12
AND X0,A #<$08,X0 ;Find YLFRAC (YL>>10), get '1'
OR X0,A B,X1 Y:(R7)+,Y1 ;Add implied '1' to YLFRAC,
; get mask K13
MPY Y1,X1,B Y:(R7)+,X0 ;Find YLINT=YL>>15, get '8' (K14)
MOVE B1,B ;Adjust sign extension
CMP X0,B Y:(R7)+,X0 ;Compare YLINT to '8', get '5' (K15)
JGT <MAXTHR_T ;If YLINT>8 set maximum THR2
SUB X0,B ;Find YLINT-5
JEQ <SETDQTHR_T ;If YLINT=5 don't shift
JLT <RSHFT_T ;If YLINT<5 shift right
REP B1 ;Else shift YLFRAC left
LSL A ; up to 3 times to get THR1
JMP <SETDQTHR_T
MAXTHR_T MOVE #<$7C,A ;Set maximum THR2 (31<<9)
JMP <SETDQTHR_T
RSHFT_T NEG B ;Find 5-YLINT
MOVE B1,N5 ;Use 5-YLINT for shift lookup
MOVE A1,X0
MOVE Y:(R5+N5),X1 ;Lookup shift constant
MPY X0,X1,A ;Shift YLFRAC right up to ? times
; to get THR1
SETDQTHR_T TFR A,B Y:(R7)+,X0 ;Get mask K16
LSR B ;Find THR2>>1
AND X0,B ;Truncate THR2>>1
ADD B,A #0,X1 ;Find THR2+(THR2>>1)
LSR A ;Find (THR2+(THR2>>1)>>1
AND X0,A Y:DQMAG,X0 ;Truncate to find DQTHR, get DQMAG
CMP X0,A #<$80,A ;Compare DQMAG to DQTHR, set TR=1
TGT X1,A ;If DQMAG>DQTHR leave TR=1,
; else DQMAG<=DQTHR, set TR=0
SAVETR_T MOVE A1,Y:TR_T ;Save TR
;**************************************************************************
; ADDB
;
; Add quantized difference signal and signal estimate
; to form reconstructed signal
;
; SR(k-n) = SE(k-n) + DQ(k-n)
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
; Output:
; SR = siii iiii | iiii iiii. | 0000 0000 (16TC)
;
;**************************************************************************
MOVE Y:SE_T,B ;Get SE
ASR B X:DQ_T,A ;Sign extend SE to get SEI, get DQS
TST A Y:DQMAG,A ;Check DQS, get DQMAG
JPL <SHFTDQ_T ;If DQS=0 continue
NEG A ;Convert DQ to 2's comp
SHFTDQ_T ASR A ;Sign extend DQ to get DQI
ADD A,B #CONST17,R7 ;Find SR=DQ+SE, update const pointer
;**************************************************************************
; ADDC
;
; Obtain sign of addition of the quantized difference
; signal and the partial signal estimate
;
; P(k) = DQ(k) + SEZ(k)
; PK0 = sign of P(k)
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
; Output:
; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE B1,Y:SR_T ;Save SR
MOVE Y:SEZ_T,B ;Get SEZ
ASR B ;Sign extend SEZ to SEZI
ADD B,A #0,B ;Find DQSEZ=DQ+SEZ,
; set SIGPK=0
TST A #<$80,X0 ;Check DQSEZ, get '1'
TEQ X0,B ;If DQSEZ=0, SIGPK=1,
; else SIGPK=0
MOVE Y:PK1_T,X0
MOVE X0,Y:PK2_T ;Delay previous PK1
MOVE Y:PK0_T,X0
MOVE X0,Y:PK1_T ;Delay previous PK0
MOVE A1,Y:PK0_T ;Save new PK0
MOVE B1,Y:SIGPK_T ;Save SIGPK
EOR X0,A Y:PK2_T,X0 ;Find PKS1=PK0**PK1
; for UPA1 & UPA2
MOVE A1,X:PKS1 ;Save PKS1
MOVE Y:PK0_T,A
EOR X0,A #3,N2 ;Find PKS2=PK0**PK2 for UPA2
MOVE A1,X:PKS2 ;Save PKS2
MOVE (R2)+ ;Adjust data buffer pointer so
MOVE (R2)+ ; that R2 points to DQ1S
;**************************************************************************
; XOR
;
; Find one bit "exclusive or" of the sign of difference
; signal and the sign of delayed difference signal.
;
; Un = sgn[DQ(k)] XOR sgn[DQ(k-n)]
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; DQnS = X:(R2+n) sXXX XXXX | XXXX XXXX | 0000 0000
;
; Outputs:
; Un = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
;**************************************************************************
;**************************************************************************
; UPB
;
; Update the coefficients of the sixth order predictor
;
; Bn(k) = [1-(2**-8)] * Bn(k-1)
; + (2**-7) * sgn[DQ(k)] * sgn[DQ(k-n)]
;
; Inputs:
; Bn = Y:(R6+n) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; Un = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
; Outputs:
; BnP = Y:(R6+n) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
MOVE Y:DQMAG,A ;Get DQMAG
TST A X:DQ_T,Y0 ;Check DQMAG, get DQS
JNE <XORUPB_T ;If DQMAG!=0 use section with XOR,
; else use section with no XOR
; (because UGBn=0 if DQMAG=0)
; UPB without XOR
MOVE Y:RSHFT+8,X1 ;Get shift constant
MOVE (R7)+ ;Adjust constant pointer
MOVE (R7)+
MOVE Y:(R7)+,X0 ;Get mask K19
DO #6,ENDLOOP_T ;Do UPB for B1-B6
MOVE X:(R2)+N2,A Y:(R6),Y1 ;Get Bn (& DQnS but don't use)
MPY X1,Y1,A ;Find Bn>>8
AND X0,A ;Truncate (Bn>>8)
NEG A ;Find UBn=ULBn=-(Bn>>8)
ADD Y1,A ;Find BnP=Bn+UBn
MOVE A1,Y:(R6)+ ;Store BnP to Bn
ENDLOOP_T JMP <UPA2_T
; UPB with XOR
XORUPB_T MOVE Y:(R7)+,X0 ;Get +gain (K17)
DO #6,UPTR_T ;Do UPB and XOR for B1-B6
MOVE X:(R2)+N2,A Y:(R6),Y1 ;Get Bn & DQnS
EOR Y0,A Y:(R7)+,X1 ;Find Un=DQS**DQnS (XOR),
; get -gain (K18)
TPL X0,A ;If Un=0 set UGBn=+gain
TMI X1,A ;If Un=1 set UGBn=-gain
MOVE Y:RSHFT+8,X1 ;Get shift constant
MPY X1,Y1,B Y:(R7)-,X1 ;Shift Bn>>8, get mask K19
AND X1,B ;Truncate (Bn>>8)
NEG B ;Find ULBn=-(Bn>>8)
ADD B,A ;Find UBn=UGBn+ULBn
ADD Y1,A ;Find BnP=Bn+UBn
MOVE A1,Y:(R6)+ ;Store BnP to Bn
UPTR_T MOVE (R7)+ ;Adjust constant pointer
MOVE (R7)+
;**************************************************************************
; UPA2
;
; Update the A2 coefficient of the second order predictor.
;
; A2(k) = [1-(2**-7)] * A2(k-1)
; + (2**-7) * { sgn[P(k)] * sgn[P(k-2)]
; - F[A1(k-1)] * sgn[P(k)] * sgn[P(k-1)] }
;
; F[A1(k)] = 4 * A1 if |A1|<=(2**-1)
; = 2 * sgn(A1) if |A1|>(2**-1)
;
; Inputs:
; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; A2 = Y:(R6+1) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; PK2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; (Note: PKS1 & PKS2 have been previously calculated)
;
; Outputs:
; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
UPA2_T MOVE X:PKS2,A ;Get PKS2=PK0**PK2
TST A #<$10,Y0 ;Check PKS2, get '+1'
MOVE #<$F0,Y1 ;Get '-1'
TPL Y0,A ;If PKS2=0, set UGA2A='+1'
TMI Y1,A ;If PKS2=1, set UGA2A='-1'
MOVE A,X1 Y:(R6)+,A ;Save UGA2A, get A1
MOVE Y:(R7)+,Y0 ;Get '+1.99' (K20)
CMP Y0,A Y:(R7)+,Y1 ;Check A1, get '-1.99' (K21)
TGT Y0,A ;If A1>=1/2, set FA1='1.99'
CMP Y1,A X:PKS1,B ;Check A1 again, get PKS1=PK0**PK1
TLT Y1,A ;If A1<=-1/2, set FA1='-1.99'
TST B #0,X0 ;Check PKS1
JMI <FINDSUM_T ;If PKS1=1, FA=FA1
NEG A ; else PKS1=0, set FA=-FA1
FINDSUM_T ADD X1,A Y:RSHFT+5,Y1 ;Find UGA2B=UGA2A+FA,
; get shift constant
MOVE A,X1
MPY X1,Y1,A Y:(R7)+,X1 ;Find UGA2B>>7, get mask K22
AND X1,A Y:SIGPK_T,B ;Truncate UGA2, get SIGPK
TST B Y:(R6),Y0 ;Check SIGPK, get A2
TMI X0,A ;If SIGPK=1, set UGA2=0
MOVE Y:RSHFT+7,X0 ;Get shift constant
MPY Y0,X0,B ;Find A2>>7
AND X1,B ;Truncate to find A2>>7
NEG B #<$D0,X0 ;Find ULA2=-(A2>>7), get A2LL
ADD B,A #<$30,X1 ;Find UA2=UGA2+ULA2, get A2UL
ADD Y0,A Y:(R7)+,Y1 ;Find A2T=A2+UA2, get -gain (K23)
;**************************************************************************
; LIMC
;
; Limit the A2 coefficient of the second order predictor.
;
; |A2(k)| <= '0.75'
;
; Inputs:
; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
; Outputs:
; A2P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
CMP X0,A Y:(R7)+,Y0 ;Check A2P, get +gain (K24)
TLT X0,A ;If A2P<-0.75, set A2P=-0.75
CMP X1,A X:PKS1,B ;Check A2P again, get PKS1=PK0**PK1
TGT X1,A ;If A2P>0.75, set A2P=0.75
MOVE A,Y:A2P_T ;Save A2P
MOVE A,Y:(R6)- ;Save A2P to A2
;**************************************************************************
; UPA1
;
; Update the A1 coefficient of the second order predictor.
;
; A1(k) = [1-(2**-8)] * A1(k-1)
; + 3 * (2**-8) * sgn[P(k)] * sgn[P(k-1)]
;
; Inputs:
; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; SIGPK = Y:(R0) = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; (Note: PKS1 has been previously calculated)
;
; Outputs:
; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
TST B Y:SIGPK_T,B ;Check PKS1, get SIGPK
TPL Y0,A ;If PKS=0, set UGA1=+gain
TMI Y1,A ;If PKS=1, set UGA1=-gain
TST B #0,X0 ;Check SIGPK
TMI X0,A ;If SIGPK=1, set UGA1=0
MOVE Y:(R6),X1 ;Get A1
MOVE Y:RSHFT+8,Y0 ;Get shift constant
MPY Y0,X1,B Y:(R7)+,X0 ;Find A1>>8, get mask K25
AND X0,B ;Truncate (A1>>8)
NEG B ;Find ULA1=-(A1>>8)
ADD B,A #<$3C,B ;Find UA1=UGA1+ULA1,
; get OME='1-(2**-4)'
ADD X1,A Y:A2P_T,X0 ;Find A1T=A1+UA1, get A2P
;**************************************************************************
; LIMD
;
; Limit the A1 coefficient of the second order predictor.
;
; |A1(k)| <= [1-(2**-4)] - A2(k)
;
; Inputs:
; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
; Outputs:
; A1P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
SUB X0,B ;Find A1UL=OME-A2P
CMP B,A B,X0 ;Check A1T
TGT X0,A ;If A1T>A1UL, set A1P=A1UL
NEG B (R2)+ ;Find A1LL=-A1UL=A2P-OME
CMP B,A B,X0 ;Check A1T again
TLT X0,A ;If A1T<A1LL, set A1P=A1LL
MOVE A1,Y:(R6)+ ;Store A1P to A1
MOVE (R6)+ ;Adjust coef pointer
;**************************************************************************
; FLOATA
;
; Converts the quantized difference signal from 15-bit
; signed magnitude to floating pt. format (11FL - sign,
; exp, and mant stored separately)
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
;
; Outputs:
; DQ0 = (11FL)
; DQ0EXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee
; DQ0MANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000
; DQ0S = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000
;
;**************************************************************************
MOVE X:DQ_T,Y0 ;Get DQS
MOVE Y:DQMAG,A ;Get MAG=DQMAG
TST A #$000E,R0 ;Check MAG, get exponent bias (14)
JNE <NORMDQ_T ;Test MAG
MOVE #<$40,A ;If MAG=0 set MANT=100000,
MOVE #0,R0 ; and EXP=0
JMP <TRUNCDQ_T
NORMDQ_T NORM R0,A ;If MAG!=0 do NORM iteration 13
NORM R0,A ; times to find MSB of MAG
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
; A1 = 01?? ???? | ???? ???0 | 0000 0000 = normalized MAG (A2=A0=0)
; R0 = 0000 0000 | 0000 eeee = exponent of normalized MAG
TRUNCDQ_T MOVE #<$7E,X0 ;Get mask
AND X0,A R0,X:(R2)+ ;Truncate MANT to 6 bits,
; save EXP to DQ1EXP
; A1 = 01mm mmm0 | 0000 0000 | 0000 0000 (A2=A0=0)
MOVE A1,X:(R2)+ ;Save MANT to DQ1MANT
MOVE Y0,X:(R2)+ ;Save DQ to DQ1S
;**************************************************************************
; FLOATB
;
; Converts the reconstructed signal from 16-bit two's
; complement to floating pt. format (11FL - sign,
; exp, and mant stored separately)
;
; Inputs:
; SR = siii iiii | iiii iiii. | 0000 0000 (16TC)
;
; Outputs:
; SR0 = (11FL)
; SR0EXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee
; SR0MANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000
; SR0S = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000
;
;**************************************************************************
MOVE #15,N2
MOVE Y:SR_T,B ;Get SR
MOVE (R2)+N2 ;Adjust data pointer
ABS B B,Y0 ;Find MAG=|SR|, save SRS
TST B #$000F,R0 ;Load exponent bias
JNE <NORMSR_T ;Test MAG
MOVE #<$40,B ;If MAG=0 set MANT=100000,
MOVE #0,R0 ; and EXP=0
JMP <TRUNCSR_T
NORMSR_T NORM R0,B ;If MAG!=0 do NORM iteration 14
NORM R0,B ; times to find MSB of MAG
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
; A1 = 01?? ???? | ???? ???0 | 0000 0000 (A2=A0=0)
; R0 = 0000 0000 | 0000 eeee = exponent of normalized MAG
TRUNCSR_T AND X0,B R0,X:(R2)+ ;Truncate MANT to 6 bits,
; save EXP to SR1EXP
; A1 = 01mm mmm0 | 0000 0000 | 0000 0000 (A2=A0=0)
MOVE B1,X:(R2)+ ;Save MANT to SR1MANT
MOVE Y0,X:(R2)+ ;Save SR to SR1S
MOVE #3,N2
MOVE Y:A2P_T,B ;Get A2P
MOVE (R2)+N2 ;Adjust data pointer
;**************************************************************************
; TONE
;
; Partial band signal detection
;
; TD(k) = 1 if A2(k) < -0.71875
; 0 otherwise
;
; Inputs:
; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
; Output:
; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
CLR A #<$D2,X0 ;Get '-.71875', set TDP=0
CMP X0,B #<$80,X1 ;Check A2P, get '1'
TLT X1,A ;If A2P<-.71875 set TDP=1, else TDP=0
MOVE A1,Y:TDP_T ;Save TDP
MOVE A1,Y:TD_T ;Save TDP to TD
;**************************************************************************
; TRIGB
;
; Predictor trigger block
;
; If TR(k) = 1, An(k)=Bn(k)=TD(k)=0
;
; Inputs:
; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; BnP = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; AnP = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
; Output:
; BnR = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; AnR = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; TDR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE Y:TR_T,B ;Get TR
TST B #0,A ;Test TR
JEQ <FUNCTF_T ;If TR=0 continue
MOVE A,Y:TD_T ;If TR=1, set TDR=0,
MOVE A,Y:(R6)+ ; and B1-B6,A1,A2=0
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
;**************************************************************************
; FUNCTF
;
; Maps quantizer output I into F(I) function
;
; |I(k)| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; ---------+---+---+---+---+---+---+---+---+
; F[I(k)] | 7 | 3 | 1 | 1 | 1 | 0 | 0 | 0 |
;
; Inputs:
; I = siii 0000 | 0000 0000 | 0000 0000
;
; Output:
; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM)
; IMAG
;
;**************************************************************************
FUNCTF_T MOVE #<$20,X0
MOVE X:IMAG,A ;Get |I|
CMP X0,A #<$50,X0 ;Test for |I|<=2
JLE <RANGE0_T
CMP X0,A #<$60,X0 ;Test for 3<=|I|<=5
JLE <RANGE1_T
CMP X0,A ;Test for |I|=6
JEQ <RANGE3_T
MOVE #<$70,A ;|I|=7, set F[I]=7
JMP <FILTA_T
RANGE3_T MOVE #<$30,A ;|I|=6, set F[I]=3
JMP <FILTA_T
RANGE1_T MOVE #<$10,A ;|I|=3,4,or 5, set F[I]=1
JMP <FILTA_T
RANGE0_T CLR A ;|I|=0,1,or 2, set F[I]=0
;**************************************************************************
; FILTA
;
; Update short term average of F(I)
;
; DMS(k) = (1 - 2**(-5)) * DMS(k-1) + 2**(-5) * F[I(k)]
;
; Inputs:
; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM)
; DMS = 0iii. ffff | ffff f000 | 0000 0000 (12SM)
;
; Output:
; DMSP = 0iii. ffff | ffff f000 | 0000 0000 (12SM)
;
;**************************************************************************
FILTA_T MOVE Y:DMS_T,Y0 ;Get DMS
SUB Y0,A A,B ;Find DIF=FI-DMS, save FI
MOVE A,X0 Y:(R7)+,Y1 ;Save DIF, get mask K26
MPY X0,Y1,A Y:(R7)+,X0 ;Find DIFSX=DIF>>5, get mask K27
AND X0,A Y:DML_T,Y1 ;Truncate DIFSX, get DML
ADD Y0,A Y:RSHFT+7,X1 ;Find DMSP=DIFSX+DMS
;**************************************************************************
; FILTB
;
; Update long term average of F(I)
;
; DML(k) = (1 - 2**(-7)) * DML(k-1) + 2**(-7) * F[I(k)]
;
; Inputs:
; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM)
; DML = 0iii. ffff | ffff fff0 | 0000 0000 (14SM)
;
; Output:
; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM)
;
;**************************************************************************
SUB Y1,B A1,Y:DMS_T ;Find DIF=FI-DML
MOVE B1,X0
MPY X0,X1,B Y:(R7)+,X0 ;Find DFISX=DIF>>7, get mask K28
AND X0,B ;Truncate DIFSX
ADD Y1,B Y:RSHFT+3,X1 ;Find DMLP=DIFSX+DML
;**************************************************************************
; SUBTC
;
; Compute magnitude of the difference of short and long
; term functions of quantizer output sequence and then
; perform threshold comparison for quantizing speed control
; parameter.
;
; AX = 1 if Y(k)>=3, TD(k)=1, & |DMS(k)-DML(k)|>(2**-3)*DML(k)
; = 0 otherwise
;
; Input:
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
; DMSP = 0iii. ffff | ffff f000 | 0000 0000 (12SM)
; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM)
; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
; Output:
; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM)
;
;**************************************************************************
SUB B,A B1,Y:DML_T ;Find DIF=DMSP-DMLP, save DML
ABS A B1,Y0 ;Find DIFM=|DIF|
MPY X1,Y0,B #<$18,Y0 ;Find DTHR=DMLP>>3, get '3'
AND X0,B #<$40,X0 ;Truncate DTHR, get '1'
CMP B,A #0,B ;Compare DIFM & DTHR, set AX=0
TGE X0,B ;If DIFM>=DTHR set AX=1
MOVE Y:TDP_T,A ;Get TDP
TST A X:Y_T,A ;Check TDP, get Y
TNE X0,B ;If TDP!=0 set AX=1
CMP Y0,A X:AP_T,X1 ;Check for Y<"3", get AP
TLT X0,B ;If Y<"3" set AX=1
;**************************************************************************
; FILTC
;
; Low pass filter of speed control parameter
;
; AP(k) = (1-2**(-4)) * AP(k-1) + AX
;
; Inputs:
; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM)
; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
; Outputs:
; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
;**************************************************************************
SUB X1,B Y:RSHFT+4,Y0 ;Find DIF=AX-AP
MOVE B1,X0
MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFSX=DIF>>4, get K29
AND X0,A Y:TR_T,B ;Truncate DIFSX, get TR
ADD X1,A #<$20,X0 ;Find APP=DIFSX+AP, get '1'
;**************************************************************************
; TRIGA
;
; Speed control trigger block
;
; AP(k) = AP(k) if TR(k)=0
; = 1 if TR(k)=1
;
; Inputs:
; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
; Outputs:
; APR = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
;**************************************************************************
TST B X:IMAG,X1 ;Check TR, get IMAG
TMI X0,A ;If TR=1 set APR=1, else APR=APP
MOVE A1,X:AP_T ;Save APR to AP
;**************************************************************************
; FUNCTW
;
; Map quantizer output into logarithmic version of scale
; factor multiplier
;
; |I(k)| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; ---------+-----+-----+-----+-----+-----+-----+-----+-----+
; W(I) |70.13|22.19|12.38| 7.00| 4.00| 2.56| 1.13|-0.75|
;
; Inputs:
; I = siii. 0000 | 0000 0000 | 0000 0000 (ADPCM format)
;
; Outputs:
; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC)
;
;**************************************************************************
MOVE Y:RSHFT+20,X0 ;Get shift constant
MPY X0,X1,A #WIBASE,R0 ;Shift IM=IMAG for lookup,
; load lookup table base
MOVE A1,N0 ;Load IM as offset
MOVE Y:RSHFT+3,X1 ;Get shift constant
MOVE X:Y_T,Y0 ;Get Y
MPY Y0,X1,B X:(R0+N0),A ;Shift Y>>3,
; get WI from lookup table
;**************************************************************************
; FILTD
;
; Update of fast quantizer scale factor
;
; YU(k) = (1 - 2**(-5)) * Y(k) + 2**(-5) * W[I(k)]
;
; Inputs:
; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC)
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Outputs:
; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
;**************************************************************************
SUB B,A ;Find DIF=WI-Y
ASR A ;Find DIFSX=DIF>>5 (actually DIF>>2)
ASR A Y:(R7)+,X0 ;Get mask K30
AND X0,A ;Truncate DIFSX
ADD Y0,A #<$50,X0 ;Find YUT=DIFSX+Y,
; get upper limit '10'
;**************************************************************************
; LIMB
;
; Limit quantizer scale factor
;
; 1.06 <= YU(k) <= 10.00
;
; Inputs:
; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Outputs:
; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
;**************************************************************************
CMP X0,A Y:(R7)+,X1 ;Check for YU>10,
; get lower limit '1.06' (K31)
TGT X0,A ;If YU>10 set YU=10
CMP X1,A Y:YL_T,Y1 ;Check for YU<1.06, get YL
TLT X1,A ;If YU<1.06 set YU=1.06
;**************************************************************************
; FILTE
;
; Update of slow quantizer scale factor
;
; YL(k) = (1 - 2**(-6)) * YL(k-1) + 2**(-6) * YU(k)
;
; Inputs:
; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
;
; Outputs:
; YLP = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
;
;**************************************************************************
TFR Y1,B A1,Y:YU_T ;Move YL, save YUP
NEG B Y:(R7)+,Y0 ;Find -YL, save YL, get mask K32
AND Y0,B ;Truncate -YL (-YL>>6)
ADD B,A Y:RSHFT+6,Y0 ;Find DIF=YUP+(-YL>>6)
MOVE A1,X1
MPY Y0,X1,A ;Find DIFSX>>6
ADD Y1,A R2,X:DATAPTR_T ;Find YLP=DIFSX+YL,
; save transmit data pointer
MOVE A1,Y:YL_T ;Save YL
;**************************************************************************
;
; Decoder
;
;**************************************************************************
DECODE MOVE #PP_R,R1 ;Set partial product ptr to WB1
MOVE X:DATAPTR_R,R2 ;Set data pointer to DQ1EXP
MOVE #COEF_R,R6 ;Set coef pointer to B1
MOVE #CONST1,R7 ;Set pointer to misc constants
;**************************************************************************
; FMULT
;
; Multiply predictor coefficients with corresponding
; quantized difference signal or reconstructed signal
;
; Data (DQn or SRn) is stored in 11FL format (separate),
; & coefficient (Bn or An) is stored in 16TC format.
;
; Computes [An(k-1) * SR(k-n)] or [Bn(k-1) * DQ(k-n)]
;
; Flow Description:
; 1. Convert 16TC An to 13SM AnMAG
; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT)
; 3. Add SRnEXP to AnEXP to get WAnEXP (5-bits)
; 4. Multiply SRnMANT with AnMANT, add '48', and truncate
; to 8-bits to get WAnMANT
; 5. Convert 13FL (WAnEXP & WAnMANT) to 15SM WAnMAG
; 6. XOR AnS with SRnS to find WAnS
; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn
;
; Input:
; SRn = (11FL)
; SRnEXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee
; SRnMANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000
; SRnS = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000
; (DQ in same format as SR)
;
; An = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; (Bn in same format as An)
;
; Output:
; WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC)
; (WBn in same format as WAn)
;
;**************************************************************************
MOVE #CONST,R0 ;Set pointer to FMULT constants
MOVE #0,Y1
DO #8,ACCUM_R ;Execute mult 8 times
; 1. Convert 16TC An to 13SM AnMAG
MOVE X:(R0)+,X1 Y:(R6),A ;Get An and mask KF1
AND X1,A X:(R0)+,X1 ;Truncate An to 13 bits (An>>2),
; get mask KF2
ABS A #$000D,R4 ;Find AnMAG, load
; exponent bias (13) into R4
AND X1,A #<$7E,X1 ;Truncate any ovrflw, get mask
; A1 = 0i.ff ffff | ffff ff00 | 0000 0000 (A2=A0=0)
; 2. Convert 13SM AnMAG to 10FL (AnEXP and AnMANT)
JNE <NORMAN_R ;Test AnMAG
MOVE #<$40,A ;If AnMAG=0, set AnMANT=1<<5,
MOVE #0,R4 ; and AnEXP=0
JMP <CONTIN_R
NORMAN_R NORM R4,A ;If AnMAG!=0 do NORM iteration
NORM R4,A ; 12 times to find MSB
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
NORM R4,A
; A1 = 01?? ???? | ???? ??00 | 0000 0000 = AnMANT
; R4 = 0000 0000 | 0000 eeee = AnEXP
CONTIN_R AND X1,A R4,B ;Truncate AnMANT to 6 bits,
; move AnEXP to B
; A1 = 01mm mmm0 | 0000 0000 | 0000 0000 (A2=A0=0)
; B1 = 0000 0000 | 0000 0000 | 0000 eeee (B2=B0=0)
; 3. Add SRnEXP to AnEXP to get WAnEXP (5-bits)
MOVE X:(R2)+,X1 A,Y0 ;Get SRnEXP
ADD X1,B X:(R2)+,X1 ;Find WAnEXP=SRnEXP+AnEXP,
; get SRnMANT
; B1 = 0000 0000 | 0000 0000 | 000e eeee (B2=B0=0)
; 4. Multiply SRnMANT with AnMANT, add '48', and truncate
; to 8-bits to get WAnMANT
; Y0 = 01mm mmm0 | 0000 0000 | 0000 0000
; X1 = 01mm mmm0 | 0000 0000 | 0000 0000
MPY Y0,X1,A X:(R0)+,X0 ;Find WAnMANT, get '48' (KF3)
; A1 = 0mmm mmmm | mmmm m000 | 0000 0000 (A2=A0=0)
; X0 = 0000 0001 | 1000 0000 | 0000 0000 = '48'
ADD X0,A X:(R0)+,X0 ;Add '48' to WAnMANT, get mask KF4
AND X0,A X:(R0)+,X0 ;Truncate WAnMANT to 8 bits,
; get '26' (KF5)
; A1 = 0mmm mmmm | m000 0000 | 0000 0000 (A2=A0=0)
; 5. Convert 13FL (WAnEXP & WAnMANT) to 15SM WAnMAG
; X0 = 0000 0000 | 0000 0000 | 0001 1010 = '26'
; B1 = 0000 0000 | 0000 0000 | 000e eeee (B2=B0=0)
SUB X0,B X:(R0)+,X0 ;Find shift offset (WAnEXP-26),
; get mask KF6
JEQ <TRUNC_R ;If offset=26 no shift
JMI <RIGHT_R ;If offset<26 do right shift
;Else offset>26, do left shift
REP B1 ;Offset>26, shift WAnMANT
LSL A ; left up to 4 times
JMP <TRUNC_R
RIGHT_R ABS B #>$0F,Y0 ;Find |offset|, get '15'
CMP Y0,B B1,N5 ;Compare |offset| to '15',
; load offset for shift
TGE Y1,A ;If |offset|>=15 WAnMAG=0
MOVE A1,X1 ;Move WAnMANT for shift
MOVE Y:(R5+N5),Y0 ;Lookup shift constant
MPY Y0,X1,A ;Shift WAnMANT right up to 14 times
; A1 = ?mmm mmmm | mmmm mmmm | ???? ???? (A2=A0=0)
TRUNC_R AND X0,A X:(R2)+,X1 Y:(R6)+,B ;Truncate WAnMAG to 15 bits,
; get SRnS & AnS
; A1 = 0iii iiii | iiii iii.f | 0000 0000 (A2=A0=0)
NEG A A1,X0 ;Find -WAnMAG, save WAnMAG
; 6. XOR AnS with SRnS to find WAnS
; B1 = sXXX XXXX | XXXX XXXX | 0000 0000 (B2=sign ext, B0=0)
; X1 = sXXX XXXX | XXXX XXXX | 0000 0000
EOR X1,B #CONST,R0 ;Find WAnS (in MSB of B),
; update pointer to constants
; 7. Convert 16SM (WAnMAG & WAnS) to 16TC WAn
TPL X0,A ;If WAnS=0 use WAnMAG, else use -WAnMAG
; A1 = siii iiii | iiii iii.f | 0000 0000 (A2=sign ext, A0=0)
MOVE A1,X:(R1)+ ;Save WAn
;**************************************************************************
; ACCUM
;
; Add predictor outputs to form the partial signal estimate
; and the signal estimate
;
; SEZ(k) = [B1(k-1) * DQ(k-1)] + ... + [B6(k-1) * DQ(k-6)]
; = WB1 + WB2 + ... + WB6
;
; SE(k) = SEZ(k) + [A1(k-1) * SR(k-1)] + [A2(k-1) * SR(k-2)]
; = SEZ + WA1 + WA2
;
; Inputs:
; WBn & WAn = X:(R1) = siii iiii | iiii iii.f | 0000 0000 (16TC)
;
; Outputs:
; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC)
; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
;**************************************************************************
ACCUM_R MOVE X:(R1)+,A ;Get WB1
MOVE X:(R1)+,X0 ;Get WB2
ADD X0,A X:(R1)+,X0 ;Accumulate WB1&WB2, get WB3
ADD X0,A X:(R1)+,X0 ;Accumulate WB3, get WB4
ADD X0,A X:(R1)+,X0 ;Accumulate WB4, get WB5
ADD X0,A X:(R1)+,X0 ;Accumulate WB5, get WB6
ADD X0,A X:(R1)+,X0 ;Accumulate WB6 to get SEZI, get WA1
TFR A,B Y:(R7)+,X1 ;Copy SEZI, get mask K1
AND X1,B X:AP_R,Y0 ;Truncate SEZI, get AP
ADD X0,A X:(R1)+,X0 ;Accumulate WA1, get WA2
ADD X0,A B1,Y:SEZ_R ;Accumulate WA2 to get SEI, save SEZ
AND X1,A #<$20,X0 ;Truncate SEI, get '1'
TFR Y0,A A1,Y:SE_R ;Move AP, save SE
;**************************************************************************
; LIMA
;
; Limit speed control parameter
;
; AL(k) = 1 if AP(k-1) > 1
; = AP(k-1) if AP(k-1) <= 1
;
; Inputs:
; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
; Outputs:
; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM)
;
;**************************************************************************
CMP X0,A Y:YL_R,B ;Test AP, get YL
TGT X0,A ;If AP>'1' set AL='1'
LSL A #<$7F,X0 ;Shift to align radix pt., get mask
AND X0,A Y:(R7)+,X0 ;Truncate AL (AP>>2), get mask K2
;**************************************************************************
; MIX
;
; Form linear combination of fast and slow quantizer
; scale factors
;
; Y(k) = AL(k) * YU(k-1) + [1 - AL(k)] * YL(k-1)
;
; Inputs:
; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
; AL = 0i.ff ffff | 0000 0000 | 0000 0000 (7SM)
; YU = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Outputs:
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
;**************************************************************************
AND X0,B A,X0 Y:YU_R,A ;Truncate YL (YL>>6), get YU
SUB B,A B,Y1 X0,X:AL_R ;Find DIF=YU-YL, save YL, get AL
ABS A A,B ;Find DIFM=|DIF|, save DIFS
MOVE A1,Y0
MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFM*AL, get mask K3
AND X0,A ;Truncate to find PRODM=(DIFM*AL)>>6
NEG A A1,X0 ;Find -PRODM, save PRODM
TST B ;Check DIFS
TPL X0,A ;If DIFS=0 PROD=PRODM,
; else PROD=-PRODM
ASL A Y1,B ;Line up radix point
ADD Y1,A ;Find Y=PROD+(YL>>6)
MOVE A,X:Y_R ;Save Y
;**************************************************************************
;
; Input ADPCM data (I) here. For simulation purposes the Input
; Word from File subroutine on the 56001 ADS board is used.
;
;**************************************************************************
MOVE #2,X0 ;Input ADPCM word (I)
JSR $E002
;**************************************************************************
; RECONST
;
; Reconstruct quantized difference signal in the log domain
;
; |I(k)| | log2|DQ(k)| - Y(k)
; --------+-------------------
; 7 | 3.32
; 6 | 2.91
; 5 | 2.52
; 4 | 2.13
; 3 | 1.66
; 2 | 1.05
; 1 | 0.031
; 0 | - inf
;
; Inputs:
; I = iiii 0000 | 0000 0000 | 0000 0000 (ADPCM format)
;
; Output:
; DQLN = siii i.fff | ffff 0000 | 0000 0000 (12TC)
; DQS = sXXX 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE #<$F0,X1
MOVE A,Y1 A,X:I_R ;Save DQS (sign of I) to Y1
EOR X1,A Y:RSHFT+20,Y0 ;Invert bits of I
TMI Y1,A ;If ^IS=1, use I, else use ^I
; A1 = 0iii 0000 | 0000 0000 | 0000 0000 (A2=?, A0=0)
MOVE A1,X0
MOVE A1,X:IMAG ;Save |I|
MPY X0,Y0,A #IQUANTAB,R4 ;Shift IMAG>>20
; A1 = 0000 0000 | 0000 0000 | 0000 0iii (A2=A0=0)
MOVE A1,N4 ;Load IMAG as offset
MOVE X:Y_R,B ; into IQUAN table, get Y
MOVE #CONST8,R7 ;Adjust constant pointer
MOVE X:(R4+N4),A ;Lookup DQLN
;**************************************************************************
; ADDA
;
; Add scale factor to log version of quantized difference
; signal
;
; DQL = DQLN + Y
;
; Inputs:
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
; DQLN = siii i.fff | ffff 0000 | 0000 0000 (12TC)
;
; Output:
; DQL = siii i.fff | ffff 0000 | 0000 0000 (12TC)
;
;**************************************************************************
MOVE Y:(R7)+,Y0 ;Get mask K8 for ADDA
AND Y0,B Y:(R7)+,X0 ;Truncate Y to 11 bits (Y<<2),
; get mask K9
ADD B,A #<$08,X1 ;Find DQL=DQLN+(Y<<2), get '1'
;**************************************************************************
; ANTILOG
;
; Convert quantized difference signal from log to linear
; domain
;
; Input:
; DQL = siii i.fff | ffff 0000 | 0000 0000 (12TC)
; DQS = sXXX 0000 | 0000 0000 | 0000 0000 (1TC)
;
; Outputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
;
;**************************************************************************
JPL <CONVLOG_R ;If DQL>=0 (DS=0) convert DQL,
; else DQL<0 (DS=1), set |DQ|=0
TFR Y1,A #<$80,X0 ;Get DQS (MSB of I), get mask
AND X0,A #0,B ;Mask off DQS, set |DQ|=0
; A1 = s000 0000 | 0000 0000 | 0000 0000 (A2=sign ext, A0=0)
MOVE B1,Y:DQMAG ;Save DQMAG=|DQ|
MOVE (R7)+ ;Adjust constant pointer
MOVE (R7)+
JMP <SAVEDQ_R
CONVLOG_R AND X0,A A,B ;Find fractional part (DMN),
; save DS
; A1 = 0000 0.fff | ffff 0000 | 0000 0000 (A2=A0=0)
OR X1,A #<$78,X0 ;Add implied '1' to DMN to
; find DQT, get integer mask
; A1 = 0000 1.fff | ffff 0000 | 0000 0000 (A2=A0=0)
AND X0,B Y:RSHFT+19,Y0 ;Find integer part (DEX),
; get shift constant
; B1 = 0iii i.000 | 0000 0000 | 0000 0000 (B2=B0=0)
MOVE B1,X0
MPY X0,Y0,B Y:(R7)+,X0 ;Shift DEX>>19, get '10' (K10)
; A1 = 0000 1.fff | ffff 0000 | 0000 0000 (A2=A0=0)
; B1 = 0000 0000 | 0000 0000 | 0000 iiii. (B2=B0=0)
SUB X0,B Y:(R7)+,X0 ;Find DQT shift=DEX-'10',
; get mask K11
JEQ <TRUNCDQM_R ;If DEX=10, no shift
JLT <SHFRDQ_R ;If DEX<10, shift right
REP B1 ;Else shift DQT left
LSL A ; up to 4 times
JMP <TRUNCDQM_R
SHFRDQ_R NEG B ;Find 10-DEX
MOVE B1,N5 ;Use 10-DEX for shift lookup
MOVE A1,Y0
MOVE Y:(R5+N5),X1 ;Lookup shift constant
MPY X1,Y0,A ;Shift DQT right up to 9 times
TRUNCDQM_R AND X0,A #<$80,B ;Truncate to find DQMAG=|DQ|,
; get sign mask
; A1 = 0iii iiii | iiii iii.0 | 0000 0000 (A2=A0=0)
AND Y1,B A1,Y:DQMAG ;Mask off DQS, save DQMAG
; B1 = s000 0000 | 0000 0000 | 0000 0000 (B2=?, B0=0)
MOVE B1,X0
OR X0,A ;Add DQS to DQMAG to get DQ
; A1 = siii iiii | iiii iii.0 | 0000 0000 (A2=?, A0=0)
SAVEDQ_R MOVE A1,X:DQ_R ;Save DQ
;**************************************************************************
; TRANS
;
; Transition detector
;
; TR(k) = 1 if TD(k)=1 and |DQ(k)|> 24 x 2**(YL(k))
; 0 otherwise
;
; Inputs:
; TD = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
;
; Output:
; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE Y:TD_R,A ;Get TD
TST A #0,A ;Check TD, set TR=0
JEQ <SAVETR_R ;If TD=0 save TR=0
; else test DQ and YL
MOVE Y:YL_R,A ;Get YL
TFR A,B Y:(R7)+,X0 ;Save YL, get mask K12
AND X0,A #<$08,X0 ;Find YLFRAC (YL>>10), get '1'
OR X0,A B,X1 Y:(R7)+,Y1 ;Add implied '1' to YLFRAC,
; get mask K13
MPY Y1,X1,B Y:(R7)+,X0 ;Find YLINT=YL>>15, get '8' (K14)
MOVE B1,B ;Adjust sign extension
CMP X0,B Y:(R7)+,X0 ;Compare YLINT to '8', get '5' (K15)
JGT <MAXTHR_R ;If YLINT>8 set maximum THR2
SUB X0,B ;Find YLINT-5
JEQ <SETDQTHR_R ;If YLINT=5 don't shift
JLT <RSHFT_R ;If YLINT<5 shift right
REP B1 ;Else shift YLFRAC left
LSL A ; up to 3 times to get THR1
JMP <SETDQTHR_R
MAXTHR_R MOVE #<$7C,A ;Set maximum THR2 (31<<9)
JMP <SETDQTHR_R
RSHFT_R NEG B ;Find 5-YLINT
MOVE B1,N5 ;Use 5-YLINT for shift lookup
MOVE A1,X0
MOVE Y:(R5+N5),X1 ;Lookup shift constant
MPY X0,X1,A ;Shift YLFRAC right up to ? times
; to get THR1
SETDQTHR_R TFR A,B Y:(R7)+,X0 ;Get mask K16
LSR B ;Find THR2>>1
AND X0,B ;Truncate THR2>>1
ADD B,A #0,X1 ;Find THR2+(THR2>>1)
LSR A ;Find (THR2+(THR2>>1)>>1
AND X0,A Y:DQMAG,X0 ;Truncate to find DQTHR, get DQMAG
CMP X0,A #<$80,A ;Compare DQMAG to DQTHR, set TR=1
TGT X1,A ;If DQMAG>DQTHR leave TR=1,
; else DQMAG<=DQTHR, set TR=0
SAVETR_R MOVE A1,Y:TR_R ;Save TR
;**************************************************************************
; ADDB
;
; Add quantized difference signal and signal estimate
; to form reconstructed signal
;
; SR(k-n) = SE(k-n) + DQ(k-n)
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
; Output:
; SR = siii iiii | iiii iiii. | 0000 0000 (16TC)
;
;**************************************************************************
MOVE Y:SE_R,B ;Get SE
ASR B X:DQ_R,A ;Sign extend SE to get SEI, get DQS
TST A Y:DQMAG,A ;Check DQS, get DQMAG
JPL <SHFTDQ_R ;If DQS=0 continue
NEG A ;Convert DQ to 2's comp
SHFTDQ_R ASR A ;Sign extend DQ to get DQI
ADD A,B #CONST17,R7 ;Find SR=DQ+SE, update const pointer
;**************************************************************************
; ADDC
;
; Obtain sign of addition of the quantized difference
; signal and the partial signal estimate
;
; P(k) = DQ(k) + SEZ(k)
; PK0 = sign of P(k)
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; SEZ = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
; Output:
; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE B1,Y:SR_R ;Save SR
MOVE Y:SEZ_R,B ;Get SEZ
ASR B ;Sign extend SEZ to SEZI
ADD B,A #0,B ;Find DQSEZ=DQ+SEZ,
; set SIGPK=0
TST A #<$80,X0 ;Check DQSEZ, get '1'
TEQ X0,B ;If DQSEZ=0, SIGPK=1,
; else SIGPK=0
MOVE Y:PK1_R,X0
MOVE X0,Y:PK2_R ;Delay previous PK1
MOVE Y:PK0_R,X0
MOVE X0,Y:PK1_R ;Delay previous PK0
MOVE A1,Y:PK0_R ;Save new PK0
MOVE B1,Y:SIGPK_R ;Save SIGPK
EOR X0,A Y:PK2_R,X0 ;Find PKS1=PK0**PK1
; for UPA1 & UPA2
MOVE A1,X:PKS1 ;Save PKS1
MOVE Y:PK0_R,A
EOR X0,A #3,N2 ;Find PKS2=PK0**PK2 for UPA2
MOVE A1,X:PKS2 ;Save PKS2
MOVE (R2)+ ;Adjust data buffer pointer so
MOVE (R2)+ ; that R2 points to DQ1S
;**************************************************************************
; XOR
;
; Find one bit "exclusive or" of the sign of difference
; signal and the sign of delayed difference signal.
;
; Un = sgn[DQ(k)] XOR sgn[DQ(k-n)]
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; DQnS = X:(R2+n) sXXX XXXX | XXXX XXXX | 0000 0000
;
; Outputs:
; Un = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
;**************************************************************************
;**************************************************************************
; UPB
;
; Update the coefficients of the sixth order predictor
;
; Bn(k) = [1-(2**-8)] * Bn(k-1)
; + (2**-7) * sgn[DQ(k)] * sgn[DQ(k-n)]
;
; Inputs:
; Bn = Y:(R6+n) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
; Un = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
; Outputs:
; BnP = Y:(R6+n) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
MOVE Y:DQMAG,A ;Get DQMAG
TST A X:DQ_R,Y0 ;Check DQMAG, get DQS
JNE <XORUPB_R ;If DQMAG!=0 use section with XOR,
; else use section with no XOR
; (because UGBn=0 if DQMAG=0)
; UPB without XOR
MOVE Y:RSHFT+8,X1 ;Get shift constant
MOVE (R7)+ ;Adjust constant pointer
MOVE (R7)+
MOVE Y:(R7)+,X0 ;Get mask K19
DO #6,ENDLOOP_R ;Do UPB for B1-B6
MOVE X:(R2)+N2,A Y:(R6),Y1 ;Get Bn (& DQnS but don't use)
MPY X1,Y1,A ;Find Bn>>8
AND X0,A ;Truncate (Bn>>8)
NEG A ;Find UBn=ULBn=-(Bn>>8)
ADD Y1,A ;Find BnP=Bn+UBn
MOVE A1,Y:(R6)+ ;Store BnP to Bn
ENDLOOP_R JMP <UPA2_R
; UPB with XOR
XORUPB_R MOVE Y:(R7)+,X0 ;Get +gain (K17)
DO #6,UPTR_R ;Do UPB and XOR for B1-B6
MOVE X:(R2)+N2,A Y:(R6),Y1 ;Get Bn & DQnS
EOR Y0,A Y:(R7)+,X1 ;Find Un=DQS**DQnS (XOR),
; get -gain (K18)
TPL X0,A ;If Un=0 set UGBn=+gain
TMI X1,A ;If Un=1 set UGBn=-gain
MOVE Y:RSHFT+8,X1 ;Get shift constant
MPY X1,Y1,B Y:(R7)-,X1 ;Shift Bn>>8, get mask K19
AND X1,B ;Truncate (Bn>>8)
NEG B ;Find ULBn=-(Bn>>8)
ADD B,A ;Find UBn=UGBn+ULBn
ADD Y1,A ;Find BnP=Bn+UBn
MOVE A1,Y:(R6)+ ;Store BnP to Bn
UPTR_R MOVE (R7)+ ;Adjust constant pointer
MOVE (R7)+
;**************************************************************************
; UPA2
;
; Update the A2 coefficient of the second order predictor.
;
; A2(k) = [1-(2**-7)] * A2(k-1)
; + (2**-7) * { sgn[P(k)] * sgn[P(k-2)]
; - F[A1(k-1)] * sgn[P(k)] * sgn[P(k-1)] }
;
; F[A1(k)] = 4 * A1 if |A1|<=(2**-1)
; = 2 * sgn(A1) if |A1|>(2**-1)
;
; Inputs:
; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; A2 = Y:(R6+1) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; SIGPK = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; PK2 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; (Note: PKS1 & PKS2 have been previously calculated)
;
; Outputs:
; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
UPA2_R MOVE X:PKS2,A ;Get PKS2=PK0**PK2
TST A #<$10,Y0 ;Check PKS2, get '+1'
MOVE #<$F0,Y1 ;Get '-1'
TPL Y0,A ;If PKS2=0, set UGA2A='+1'
TMI Y1,A ;If PKS2=1, set UGA2A='-1'
MOVE A,X1 Y:(R6)+,A ;Save UGA2A, get A1
MOVE Y:(R7)+,Y0 ;Get '+1.99' (K20)
CMP Y0,A Y:(R7)+,Y1 ;Check A1, get '-1.99' (K21)
TGT Y0,A ;If A1>=1/2, set FA1='1.99'
CMP Y1,A X:PKS1,B ;Check A1 again, get PKS1=PK0**PK1
TLT Y1,A ;If A1<=-1/2, set FA1='-1.99'
TST B #0,X0 ;Check PKS1
JMI <FINDSUM_R ;If PKS1=1, FA=FA1
NEG A ; else PKS1=0, set FA=-FA1
FINDSUM_R ADD X1,A Y:RSHFT+5,Y1 ;Find UGA2B=UGA2A+FA,
; get shift constant
MOVE A,X1
MPY X1,Y1,A Y:(R7)+,X1 ;Find UGA2B>>7, get mask K22
AND X1,A Y:SIGPK_R,B ;Truncate UGA2, get SIGPK
TST B Y:(R6),Y0 ;Check SIGPK, get A2
TMI X0,A ;If SIGPK=1, set UGA2=0
MOVE Y:RSHFT+7,X0 ;Get shift constant
MPY Y0,X0,B ;Find A2>>7
AND X1,B ;Truncate to find A2>>7
NEG B #<$D0,X0 ;Find ULA2=-(A2>>7), get A2LL
ADD B,A #<$30,X1 ;Find UA2=UGA2+ULA2, get A2UL
ADD Y0,A Y:(R7)+,Y1 ;Find A2T=A2+UA2, get -gain (K23)
;**************************************************************************
; LIMC
;
; Limit the A2 coefficient of the second order predictor.
;
; |A2(k)| <= '0.75'
;
; Inputs:
; A2T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
; Outputs:
; A2P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
CMP X0,A Y:(R7)+,Y0 ;Check A2P, get +gain (K24)
TLT X0,A ;If A2P<-0.75, set A2P=-0.75
CMP X1,A X:PKS1,B ;Check A2P again, get PKS1=PK0**PK1
TGT X1,A ;If A2P>0.75, set A2P=0.75
MOVE A,Y:A2P_R ;Save A2P
MOVE A,Y:(R6)- ;Save A2P to A2
;**************************************************************************
; UPA1
;
; Update the A1 coefficient of the second order predictor.
;
; A1(k) = [1-(2**-8)] * A1(k-1)
; + 3 * (2**-8) * sgn[P(k)] * sgn[P(k-1)]
;
; Inputs:
; A1 = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; SIGPK = Y:(R0) = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; PK0 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; PK1 = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
; (Note: PKS1 has been previously calculated)
;
; Outputs:
; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
TST B Y:SIGPK_R,B ;Check PKS1, get SIGPK
TPL Y0,A ;If PKS=0, set UGA1=+gain
TMI Y1,A ;If PKS=1, set UGA1=-gain
TST B #0,X0 ;Check SIGPK
TMI X0,A ;If SIGPK=1, set UGA1=0
MOVE Y:(R6),X1 ;Get A1
MOVE Y:RSHFT+8,Y0 ;Get shift constant
MPY Y0,X1,B Y:(R7)+,X0 ;Find A1>>8, get mask K25
AND X0,B ;Truncate (A1>>8)
NEG B ;Find ULA1=-(A1>>8)
ADD B,A #<$3C,B ;Find UA1=UGA1+ULA1,
; get OME='1-(2**-4)'
ADD X1,A Y:A2P_R,X0 ;Find A1T=A1+UA1, get A2P
;**************************************************************************
; LIMD
;
; Limit the A1 coefficient of the second order predictor.
;
; |A1(k)| <= [1-(2**-4)] - A2(k)
;
; Inputs:
; A1T = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
; Outputs:
; A1P = Y:(R6) = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
;**************************************************************************
SUB X0,B ;Find A1UL=OME-A2P
CMP B,A B,X0 ;Check A1T
TGT X0,A ;If A1T>A1UL, set A1P=A1UL
NEG B (R2)+ ;Find A1LL=-A1UL=A2P-OME
CMP B,A B,X0 ;Check A1T again
TLT X0,A ;If A1T<A1LL, set A1P=A1LL
MOVE A1,Y:(R6)+ ;Store A1P to A1
MOVE (R6)+ ;Adjust coef pointer
;**************************************************************************
; FLOATA
;
; Converts the quantized difference signal from 15-bit
; signed magnitude to floating pt. format (11FL - sign,
; exp, and mant stored separately)
;
; Inputs:
; DQ = siii iiii | iiii iii.0 | 0000 0000 (15SM)
;
; Outputs:
; DQ0 = (11FL)
; DQ0EXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee
; DQ0MANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000
; DQ0S = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000
;
;**************************************************************************
MOVE X:DQ_R,Y0 ;Get DQS
MOVE Y:DQMAG,A ;Get MAG=DQMAG
TST A #$000E,R0 ;Check MAG, get exponent bias (14)
JNE <NORMDQ_R ;Test MAG
MOVE #<$40,A ;If MAG=0 set MANT=100000,
MOVE #0,R0 ; and EXP=0
JMP <TRUNCDQ_R
NORMDQ_R NORM R0,A ;If MAG!=0 do NORM iteration 13
NORM R0,A ; times to find MSB of MAG
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
; A1 = 01?? ???? | ???? ???0 | 0000 0000 = normalized MAG (A2=A0=0)
; R0 = 0000 0000 | 0000 eeee = exponent of normalized MAG
TRUNCDQ_R MOVE #<$7E,X0 ;Get mask
AND X0,A R0,X:(R2)+ ;Truncate MANT to 6 bits,
; save EXP to DQ1EXP
; A1 = 01mm mmm0 | 0000 0000 | 0000 0000 (A2=A0=0)
MOVE A1,X:(R2)+ ;Save MANT to DQ1MANT
MOVE Y0,X:(R2)+ ;Save DQ to DQ1S
;**************************************************************************
; FLOATB
;
; Converts the reconstructed signal from 16-bit two's
; complement to floating pt. format (11FL - sign,
; exp, and mant stored separately)
;
; Inputs:
; SR = siii iiii | iiii iiii. | 0000 0000 (16TC)
;
; Outputs:
; SR0 = (11FL)
; SR0EXP = X:(R2) = 0000 0000 | 0000 0000 | 0000 eeee
; SR0MANT = X:(R2+1) = 01mm mmm0 | 0000 0000 | 0000 0000
; SR0S = X:(R2+2) = sXXX XXXX | XXXX XXXX | 0000 0000
;
;**************************************************************************
MOVE #15,N2
MOVE Y:SR_R,B ;Get SR
MOVE (R2)+N2 ;Adjust data pointer
ABS B B,Y0 ;Find MAG=|SR|, save SRS
TST B #$000F,R0 ;Load exponent bias
JNE <NORMSR_R ;Test MAG
MOVE #<$40,B ;If MAG=0 set MANT=100000,
MOVE #0,R0 ; and EXP=0
JMP <TRUNCSR_R
NORMSR_R NORM R0,B ;If MAG!=0 do NORM iteration 14
NORM R0,B ; times to find MSB of MAG
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
NORM R0,B
; A1 = 01?? ???? | ???? ???0 | 0000 0000 = normalized MAG (A2=A0=0)
; R0 = 0000 0000 | 0000 eeee = exponent of normalized MAG
TRUNCSR_R AND X0,B R0,X:(R2)+ ;Truncate MANT to 6 bits,
; save EXP to SR1EXP
; A1 = 01mm mmm0 | 0000 0000 | 0000 0000 (A2=A0=0)
MOVE B1,X:(R2)+ ;Save MANT to SR1MANT
MOVE Y0,X:(R2)+ ;Save SR to SR1S
MOVE #3,N2
MOVE Y:A2P_R,B ;Get A2P
MOVE (R2)+N2 ;Adjust data pointer
;**************************************************************************
; TONE
;
; Partial band signal detection
;
; TD(k) = 1 if A2(k) < -0.71875
; 0 otherwise
;
; Inputs:
; A2P = si.ff ffff | ffff ffff | 0000 0000 (16TC)
;
; Output:
; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
CLR A #<$D2,X0 ;Get '-.71875', set TDP=0
CMP X0,B #<$80,X1 ;Check A2P, get '1'
TLT X1,A ;If A2P<-.71875 set TDP=1, else TDP=0
MOVE A1,Y:TDP_R ;Save TDP
MOVE A1,Y:TD_R ;Save TDP to TD
;**************************************************************************
; TRIGB
;
; Predictor trigger block
;
; If TR(k) = 1, An(k)=Bn(k)=TD(k)=0
;
; Inputs:
; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; BnP = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; AnP = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
; Output:
; BnR = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; AnR = si.ff ffff | ffff ffff | 0000 0000 (16TC)
; TDR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
;**************************************************************************
MOVE Y:TR_R,B ;Get TR
TST B #0,A ;Test TR
JEQ <FUNCTF_R ;If TR=0 continue
MOVE A,Y:TD_R ;If TR=1, set TDR=0,
MOVE A,Y:(R6)+ ; and B1-B6,A1,A2=0
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
MOVE A,Y:(R6)+
;**************************************************************************
; FUNCTF
;
; Maps quantizer output I into F(I) function
;
; |I(k)| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; ---------+---+---+---+---+---+---+---+---+
; F[I(k)] | 7 | 3 | 1 | 1 | 1 | 0 | 0 | 0 |
;
; Inputs:
; I = siii 0000 | 0000 0000 | 0000 0000
;
; Output:
; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM)
; IMAG
;
;**************************************************************************
FUNCTF_R MOVE #<$20,X0
MOVE X:IMAG,A ;Get |I|
CMP X0,A #<$50,X0 ;Test for |I|<=2
JLE <RANGE0_R
CMP X0,A #<$60,X0 ;Test for 3<=|I|<=5
JLE <RANGE1_R
CMP X0,A ;Test for |I|=6
JEQ <RANGE3_R
MOVE #<$70,A ;|I|=7, set F[I]=7
JMP <FILTA_R
RANGE3_R MOVE #<$30,A ;|I|=6, set F[I]=3
JMP <FILTA_R
RANGE1_R MOVE #<$10,A ;|I|=3,4,or 5, set F[I]=1
JMP <FILTA_R
RANGE0_R CLR A ;|I|=0,1,or 2, set F[I]=0
;**************************************************************************
; FILTA
;
; Update short term average of F(I)
;
; DMS(k) = (1 - 2**(-5)) * DMS(k-1) + 2**(-5) * F[I(k)]
;
; Inputs:
; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM)
; DMS = 0iii. ffff | ffff f000 | 0000 0000 (12SM)
;
; Output:
; DMSP = 0iii. ffff | ffff f000 | 0000 0000 (12SM)
;
;**************************************************************************
FILTA_R MOVE Y:DMS_R,Y0 ;Get DMS
SUB Y0,A A,B ;Find DIF=FI-DMS, save FI
MOVE A,X0 Y:(R7)+,Y1 ;Save DIF, get mask K26
MPY X0,Y1,A Y:(R7)+,X0 ;Find DIFSX=DIF>>5, get mask K27
AND X0,A Y:DML_R,Y1 ;Truncate DIFSX, get DML
ADD Y0,A Y:RSHFT+7,X1 ;Find DMSP=DIFSX+DMS
;**************************************************************************
; FILTB
;
; Update long term average of F(I)
;
; DML(k) = (1 - 2**(-7)) * DML(k-1) + 2**(-7) * F[I(k)]
;
; Inputs:
; FI = 0iii. 0000 | 0000 0000 | 0000 0000 (3SM)
; DML = 0iii. ffff | ffff fff0 | 0000 0000 (14SM)
;
; Output:
; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM)
;
;**************************************************************************
SUB Y1,B A1,Y:DMS_R ;Find DIF=FI-DML
MOVE B1,X0
MPY X0,X1,B Y:(R7)+,X0 ;Find DFISX=DIF>>7, get mask K28
AND X0,B ;Truncate DIFSX
ADD Y1,B Y:RSHFT+3,X1 ;Find DMLP=DIFSX+DML
;**************************************************************************
; SUBTC
;
; Compute magnitude of the difference of short and long
; term functions of quantizer output sequence and then
; perform threshold comparison for quantizing speed control
; parameter.
;
; AX = 1 if Y>=3, TDP=1, & |DMSP-DMLP|>(2**-3)*DMLP
; = 0 otherwise
;
; Input:
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
; DMSP = 0iii. ffff | ffff f000 | 0000 0000 (12SM)
; DMLP = 0iii. ffff | ffff fff0 | 0000 0000 (14SM)
; TDP = i000 0000 | 0000 0000 | 0000 0000 (1TC)
;
; Output:
; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM)
;
;**************************************************************************
SUB B,A B1,Y:DML_R ;Find DIF=DMSP-DMLP, save DML
ABS A B1,Y0 ;Find DIFM=|DIF|
MPY X1,Y0,B #<$18,Y0 ;Find DTHR=DMLP>>3, get '3'
AND X0,B #<$40,X0 ;Truncate DTHR, get '1'
CMP B,A #0,B ;Compare DIFM & DTHR, set AX=0
TGE X0,B ;If DIFM>=DTHR set AX=1
MOVE Y:TDP_R,A ;Get TDP
TST A X:Y_R,A ;Check TDP, get Y
TNE X0,B ;If TDP!=0 set AX=1
CMP Y0,A X:AP_R,X1 ;Check for Y<"3", get AP
TLT X0,B ;If Y<"3" set AX=1
;**************************************************************************
; FILTC
;
; Low pass filter of speed control parameter
;
; AP(k) = (1-2**(-4)) * AP(k-1) + AX
;
; Inputs:
; AX = 0i0.0 0000 | 0000 0000 | 0000 0000 (1SM)
; AP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
; Outputs:
; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
;**************************************************************************
SUB X1,B Y:RSHFT+4,Y0 ;Find DIF=AX-AP
MOVE B1,X0
MPY X0,Y0,A Y:(R7)+,X0 ;Find DIFSX=DIF>>4, get K29
AND X0,A Y:TR_R,B ;Truncate DIFSX, get TR
ADD X1,A #<$20,X0 ;Find APP=DIFSX+AP, get '1'
;**************************************************************************
; TRIGA
;
; Speed control trigger block
;
; AP(k) = AP(k) if TR(k)=0
; = 1 if TR(k)=1
;
; Inputs:
; TR = i000 0000 | 0000 0000 | 0000 0000 (1TC)
; APP = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
; Outputs:
; APR = 0ii.f ffff | fff0 0000 | 0000 0000 (10SM)
;
;**************************************************************************
TST B X:IMAG,X1 ;Check TR, get IMAG
TMI X0,A ;If TR=1 set APR=1, else APR=APP
MOVE A1,X:AP_R ;Save APR to AP
;**************************************************************************
; FUNCTW
;
; Map quantizer output into logarithmic version of scale
; factor multiplier
;
; |I(k)| | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
; ---------+-----+-----+-----+-----+-----+-----+-----+-----+
; W(I) |70.13|22.19|12.38| 7.00| 4.00| 2.56| 1.13|-0.75|
;
; Inputs:
; I = siii. 0000 | 0000 0000 | 0000 0000 (ADPCM format)
;
; Outputs:
; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC)
;
;**************************************************************************
MOVE Y:RSHFT+20,X0 ;Get shift constant
MPY X0,X1,A #WIBASE,R0 ;Shift IM=IMAG for lookup,
; load lookup table base
MOVE A1,N0 ;Load IM as offset
MOVE Y:RSHFT+3,X1 ;Get shift constant
MOVE X:Y_R,Y0 ;Get Y
MPY Y0,X1,B X:(R0+N0),A ;Shift Y>>3,
; get WI from lookup table
;**************************************************************************
; FILTD
;
; Update of fast quantizer scale factor
;
; YU(k) = (1 - 2**(-5)) * Y(k) + 2**(-5) * W[I(k)]
;
; Inputs:
; WI = siii iiii. | ffff 0000 | 0000 0000 (12TC)
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Outputs:
; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
;**************************************************************************
SUB B,A ;Find DIF=WI-Y
ASR A ;Find DIFSX=DIF>>5 (actually DIF>>2)
ASR A Y:(R7)+,X0 ;Get mask K30
AND X0,A ;Truncate DIFSX
ADD Y0,A #<$50,X0 ;Find YUT=DIFSX+Y,
; get upper limit '10'
;**************************************************************************
; LIMB
;
; Limit quantizer scale factor
;
; 1.06 <= YU(k) <= 10.00
;
; Inputs:
; YUT = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Outputs:
; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
;**************************************************************************
CMP X0,A Y:(R7)+,X1 ;Check for YU>10,
; get lower limit '1.06' (K31)
TGT X0,A ;If YU>10 set YU=10
CMP X1,A Y:YL_R,Y1 ;Check for YU<1.06, get YL
TLT X1,A ;If YU<1.06 set YU=1.06
;**************************************************************************
; FILTE
;
; Update of slow quantizer scale factor
;
; YL(k) = (1 - 2**(-6)) * YL(k-1) + 2**(-6) * YU(k)
;
; Inputs:
; YUP = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
; YL = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
;
; Outputs:
; YLP = 0iii i.fff | ffff ffff | ffff 0000 (19SM)
;
;**************************************************************************
TFR Y1,B A1,Y:YU_R ;Move YL, save YUP
NEG B Y:(R7)+,Y0 ;Find -YL, save YL, get mask K32
AND Y0,B #CONST4,R7 ;Truncate -YL (-YL>>6),
; adjust constant pointer
ADD B,A Y:RSHFT+6,Y0 ;Find DIF=YUP+(-YL>>6)
MOVE A1,X1
MPY Y0,X1,A #$002100,Y0 ;Find DIFSX>>6, get bias
ADD Y1,A Y:LAW,B ;Find YLP=DIFSX+YL
MOVE A1,Y:YL_R ;Save YL
;**************************************************************************
; COMPRESS
;
; Convert from uniform PCM to A-law or mu-law PCM (according to
; Recommendation G.711). For further details see Motorola
; application bulletin "Logarithmic/Linear Conversion
; Routines for DSP56000/1".
;
; Input:
; SR = siii iiii | iiii iiii. | 0000 0000 (16TC)
;
; Output:
; SP = psss qqqq | 0000 0000 | 0000 0000 (PCM log format)
;
;**************************************************************************
TST B Y:SR_R,A ;Adjust constant pointer
JNE <ALAW_R
; Linear to log routine for mu-law
ABS A A,B ;Find |SR|, save sign
ADD Y0,A ;Add bias
ASL A #TAB+7,R0 ;Shift << 2, get seg ptr
ASL A X:TAB+3,X0 ; and get max. word
TES X0,A ;If overflow in extension
; set the maximum PCM word
NORM R0,A ;Find MSB of data
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
ASL A #<$20,Y0
LSL B A1,X0
MPY X0,Y0,A X:(R0),X1
AND X1,A
ROR A
NOT A #<$FF,X0
AND X0,A
MOVE A1,A
JMP <SAVESP_R
; Linear to log routine for A-law
ALAW_R ABS A A,B ;Find |SR|, save sign
TST B #$000100,X0
JPL <NOSUB_R
SUB X0,A
NOSUB_R MOVE #$7FFE00,X0
AND X0,A
ASL A #TAB+7,R0 ;Shift << 2, get seg ptr
ASL A X:TAB+3,X0 ; and get max. word
TES X0,A ;If overflow in extension
; set the maximum PCM word
NORM R0,A ;Find MSB of data
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
JNR <SEGOK_R
MOVE (R0)-
SEGOK_R LSL A #<$20,Y0
LSL B A1,X0
MPY X0,Y0,A X:(R0),X1
AND X1,A
ROR A #<$D5,Y1
EOR Y1,A #<$FF,X0 ;Invert even bits & sign
AND X0,A
MOVE A1,A
SAVESP_R MOVE A1,X:SP_R
;**************************************************************************
; EXPAND
;
; Convert A-law or mu-law PCM to uniform PCM (according to
; Recommendation G.711). For further details see Motorola
; application bulletin "Logarithmic/Linear Conversion
; Routines for DSP56000/1".
;
; Input:
; SP = psss qqqq | 0000 0000 | 0000 0000 (PCM log format)
;
; Output:
; SLX = siii iiii | iiii ii.00 | 0000 0000 (14TC)
;
;**************************************************************************
MOVE A,X0 Y:(R7)+,Y1 ;Get shift constant K4
MPY X0,Y1,A Y:(R7)+,X1 ;Shift S to 8 lsb's of A1, get K5
AND X1,A Y:SE_R,B ;Mask off sign of S, get SE
ASR B A1,N3 ;Sign extend SE, load |S| as offset
CMPM Y1,A ;Check sign of S
MOVE X:(R3+N3),A ;Lookup |SLX| from ROM table
JGE <SUBTA_R ;If S=0, SLX=|SLX|
NEG A ;If S=1, SLX=-|SLX|
;**************************************************************************
; SUBTA
;
; Compute difference signal by subtracting signal estimate
; from input signal
;
; DX(k) = SLX(k) - SE(k)
;
; Inputs:
; SLX = siii iiii | iiii ii.00 | 0000 0000 (14TC)
; SE = siii iiii | iiii iii.0 | 0000 0000 (15TC)
;
; Output:
; DX = siii iiii | iiii iiii. | 0000 0000 (16TC)
;**************************************************************************
SUBTA_R ASR A Y:(R7)+,X1 ;Sign extend SLX, get mask K6
ASR A #$000E,R0 ;Sign extend SE again, get exp bias (14)
SUB B,A X:Y_R,B ;Find DX=SLX-SE, get Y
;**************************************************************************
; LOG
;
; Convert difference signal from the linear to the log
; domain
;
; Input:
; DX = siii iiii | iiii iiii. | 0000 0000 (16TC)
;
; Outputs:
; DLX = 0iii i.fff | ffff 0000 | 0000 0000 (11SM)
; DSX = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
;**************************************************************************
ABS A A,Y1 ;Find DQM=|D|, save DSX to Y1
JNE <NORMEXP_R ;Check for DQM=0
CLR A (R7)+ ;If DQM=0 set DL=0,
MOVE Y:(R7),X0 ; get mask K8,
JMP <SUBTB_R ; and continue
NORMEXP_R NORM R0,A ;If DQM!=0, do norm iteration
NORM R0,A ; 14 times to find MSB of DQM
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
NORM R0,A
; A1 = 01?? ???? | ???? ???? | 0000 0000 = normalized DQM (A2=A0=0)
; R0 = 0000 0000 | 0000 eeee = exponent of normalized DQM
; Get rid of leading "1" in normalized DQM
; Truncate mantissa to 7 bits and combine with exponent
AND X1,A Y:LSHFT-19,X0 ;Truncate MANT, get EXP shift
; A1 = 00mm mmmm | m000 0000 | 0000 0000 (A2=A0=0)
MOVE R0,X1 ;Move EXP to X1
MPY X0,X1,A A,X1 Y:(R7)+,Y0 ;Shift EXP<<19, save MANT to X1,
; get mask K7
MOVE A0,A ;Move EXP to A1
; A1 = 0eee e000 | 0000 0000 | 0000 0000 (A2=A0=0)
MAC Y0,X1,A Y:(R7),X0 ;Shift MANT>>3 & combine with EXP,
; get mask K8
; A1 = 0eee e.mmm | mmmm 0000 | 0000 0000 (A2=A0=0)
; = 0iii i.fff | ffff 0000 | 0000 0000 (A2=A0=0)
;**************************************************************************
; SUBTB
;
; Scale log version of difference signal by subtracting
; scale factor
;
; DLNX = DLX - Y
;
; Inputs:
; DLX = 0iii i.fff | ffff 0000 | 0000 0000 (11SM)
; Y = 0iii i.fff | ffff ff00 | 0000 0000 (13SM)
;
; Output:
; DLNX = siii i.fff | ffff 0000 | 0000 0000 (12TC)
;
;**************************************************************************
SUBTB_R AND X0,B #QUANTAB,R0 ;Truncate Y to 11 bits (Y>>2),
; get quantization table base
SUB B,A #>QUANTAB+2,X1 ;Find DLNX=DLX-Y
;**************************************************************************
; SYNC
;
; Re-encode output PCM sample in decoder for synchronous
; tandem coding
;
; Inputs:
; I = siii 0000 | 0000 0000 | 0000 0000 (ADPCM format)
; SP = psss qqqq | 0000 0000 | 0000 0000 (PCM log format)
; DLNX = siii i.fff | ffff 0000 | 0000 0000 (12TC)
; DSX = sXXX XXXX | XXXX XXXX | 0000 0000 (1TC)
;
; Output:
; SD = psss qqqq | 0000 0000 | 0000 0000 (PCM log format)
;
;**************************************************************************
MOVE X:(R0)+,X0 ;Get quan table value
TSTDLN_R CMP X0,A X:(R0)+,X0 ;Compare to DLNX
JGE <TSTDLN_R ;If value<DLNX try next range
MOVE R0,A ;When range found...
; subtract pointer from
SUB X1,A Y:LSHFT-19,X0 ; base to get |ID|
; A1 = 0000 0000 | 0000 0000 | 0000 0iii (A2=A0=0)
MOVE A1,X1
MPY X0,X1,A Y1,B ;Shift |ID|<<19, result is
; in A0, move DSX into B
; A0 = 00ii i000 | 0000 0000 | 0000 0000
MOVE A0,A
; A1 = 00ii i000 | 0000 0000 | 0000 0000 (A2=A0=0)
TST A #<$78,X0 ;Check |ID|, get invert mask
JEQ <INVERT_R ;If |ID|=0 invert bits
TST B ;If |ID|!=0, check DSX
JPL <IOUT_R ;If DSX=1 don't invert |ID|
INVERT_R EOR X0,A ;If DSX=0 or |ID|=0,
; invert |ID|
IOUT_R MOVE #<$40,X0
EOR X0,A X:I_R,B ;Invert MSB of ID, get I
TST B A1,A ;Adjust sign extension, check IS
JMI <ANDW7_R ;If IS=1, AND with 7
MOVE #<$80,X0 ;If IS=0,
EOR X0,B ; find IM=I+8
JMP <FIXS_R
ANDW7_R MOVE #<$70,X0
AND X0,B ;Find IM=I&7
FIXS_R LSR B
MOVE B1,B
; A1 = 0iii i000 | 0000 0000 | 0000 0000 (A2=A0=0)
; B1 = 0iii i000 | 0000 0000 | 0000 0000 (B2=B0=0)
SUB B,A Y:LAW,B
TST B
JNE <ALAWDEC_R
TST A X:SP_R,A ;Compare ID and IM, get SP
JEQ <SAVESD_R ;If ID=IM, SD=SP
JLT <SPPLUS_R ;If ID<IM, SD=SP+
;Else ID>IM, SD=SP-
TST A #<$80,X0
JEQ <SAVESD_R ;If SP=0, SP-=SP
CMP X0,A #<$FF,X0
JEQ <INCSP_R ;If SP=$80, SP-=SP+1
CMP X0,A #<$7F,X0
JEQ <SETNEG1_R ;If SP=$FF, SP-=$7E
CMP X0,A
JEQ <DECSP_R ;If SP=$7F, SP-=SP-1
TST A
JPL <DECSP_R ;Else if SPS=1, SP-=SP-1
JMP <INCSP_R ;Else SPS=0, SP-=SP+1
SPPLUS_R TST A #<$80,X0
JEQ <INCSP_R ;If SP=0, SP+=SP+1
CMP X0,A #<$FF,X0
JEQ <SAVESD_R ;If SP=$80, SP+=SP
CMP X0,A #<$7F,X0
JEQ <DECSP_R ;If SP=$FF, SP+=SP-1
CMP X0,A
JEQ <SET1_R ;If SP=$7F, SP+=$FE
TST A
JPL <INCSP_R ;Else if SPS=1, SP+=SP+1
JMP <DECSP_R ;Else SPS=0, SP+=SP-1
INCSP_R MOVE #<$01,X0
ADD X0,A ;Find SD=SP+1
JMP <SAVESD_R
DECSP_R MOVE #<$01,X0
SUB X0,A ;Find SD=SP-1
JMP <SAVESD_R
SET1_R MOVE #<$FE,A ;Find SD=$FE
JMP <SAVESD_R
SETNEG1_R MOVE #<$7E,A ;Find SD=$7E
JMP <SAVESD_R
ALAWDEC_R MOVE A,B
MOVE X:SP_R,A ;Get SP
MOVE #<$55,X0
EOR X0,A
TST B
JEQ <INVEVEN_R ;If ID=IM, SD=SP
JLT <SPPLUSA_R ;If ID<IM, SD=SP+
;Else ID>IM, SD=SP-
TST A #<$80,X0
JEQ <INCSPA_R ;If SP=0, SP-=SP+1
CMP X0,A #<$FF,X0
JEQ <SETNEG0_R ;If SP=$80, SP-=0
CMP X0,A #<$7F,X0
JEQ <DECSPA_R ;If SP=$FF, SP-=SP-1
CMP X0,A
JEQ <INVEVEN_R ;If SP=$7F, SP-=SP
TST A
JMI <DECSPA_R ;Else if SPS=0, SP-=SP-1
JMP <INCSPA_R ;Else SPS=1, SP-=SP+1
SPPLUSA_R TST A #<$80,X0
JEQ <SET0_R ;If SP=0, SP+=$80
CMP X0,A #<$FF,X0
JEQ <INCSPA_R ;If SP=$80, SP+=SP+1
CMP X0,A #<$7F,X0
JEQ <INVEVEN_R ;If SP=$FF, SP+=SP
CMP X0,A
JEQ <DECSPA_R ;If SP=$7F, SP+=SP-1
TST A
JMI <INCSPA_R ;Else if SPS=0, SP+=SP+1
JMP <DECSPA_R ;Else SPS=1, SP+=SP-1
INCSPA_R MOVE #<$01,X0
ADD X0,A ;Find SD=SP+1
JMP <INVEVEN_R
DECSPA_R MOVE #<$01,X0
SUB X0,A ;Find SD=SP-1
JMP <INVEVEN_R
SET0_R MOVE #<$80,A ;Find SD=$80
JMP <INVEVEN_R
SETNEG0_R CLR A ;Find SD=0
INVEVEN_R MOVE #<$55,X0
EOR X0,A
SAVESD_R MOVE #2,X0
JSR $E004
MOVE R2,X:DATAPTR_R
JMP <ENCODE
;**************************************************************************
; INIT
;
; Initialize program variables, transfer data tables to X and Y
; memory, and set up registers
;
;**************************************************************************
INIT MOVE #0,R0
MOVE #0,R4
REP #$7F
MOVE A,X:(R0)+ A,Y:(R4)+ ;Clear X & Y internal RAM
; X memory initialization
MOVE #$3E2000,X0
MOVE X0,X:AP_T ;Initialize AP_T & AP_R
MOVE A0,X:AP_R
MOVE #DATA_T,A0 ;Set transmit data pointer
MOVE A0,X:DATAPTR_T ; to start of transmit data buffer
MOVE #DATA_R,A0 ;Set receive data pointer
MOVE A0,X:DATAPTR_R ; to start of receive data buffer
MOVE #VARINIT,R0
MOVE #QUANTAB,R3
DO #38,XTABLES
MOVE P:(R0)+,X0 ;Transfer constant tables
MOVE X0,X:(R3)+ ; into X memory
XTABLES
MOVE #DATA_T+1,R3
MOVE #<$4,X0
MOVE #<$8,X1
DO #6,XBUFFER1
MOVE X0,X:(R3)+ ;Initialize SRnMANT and SRnS vars
MOVE X1,X:(R3)+ ; in the transmit data buffer
MOVE (R3)+
XBUFFER1
MOVE X0,X:(R3)+ ;Initialize SR1MANT (transmit)
MOVE (R3)+
MOVE (R3)+
MOVE X0,X:(R3)+ ;Initialize SR2MANT (transmit)
MOVE #DATA_R+1,R3
DO #6,XBUFFER2
MOVE X0,X:(R3)+ ;Initialize SRnMANT and SRnS vars
MOVE X1,X:(R3)+ ; in the receive data buffer
MOVE (R3)+
XBUFFER2
MOVE X0,X:(R3)+ ;Initialize SR1MANT (receive)
MOVE (R3)+
MOVE (R3)+
MOVE X0,X:(R3)+ ;Initialize SR2MANT (receive)
; Y memory initialization
MOVE #$088000,X0
MOVE X0,Y:YU_T ;Initialize YU_T,
MOVE X0,Y:YL_T ; & YL_T
MOVE X0,Y:YU_R ;Initialize YU_R,
MOVE X0,Y:YL_R ; & YL_R
MOVE #RSHFT,R3
DO #56,YTABLES
MOVE P:(R0)+,X0 ;Transfer constant tables
MOVE X0,Y:(R3)+ ; into Y memory
YTABLES
; Address register initialization
MOVEC #7,M1 ;Set partial product buffer for mod(7)
MOVEC #23,M2 ;Set data buffer for mod(23)
MOVEC #7,M6 ;Set coef buffer for mod(7)
MOVEC #$7F,M3 ;Set PCM table for mod(127)
MOVE #0,A ;Select mu-law or A-law,
MOVE A,Y:LAW ; for mu-law set LAW=0 (default),
; for A-law set LAW!=0
TST A #$100,R3 ;If LAW=0 select mu-law table
JEQ <SETR5 ; base (in X ROM), otherwise
MOVE #$180,R3 ; select A-law table base
SETR5 MOVE #RSHFT,R5 ;Set right shift table base
RTS
;QUANTAB
VARINIT DC $F84000 ;-0.98
DC $050000 ;0.62
DC $0B2000 ;1.38
DC $0F6000 ;1.91
DC $12C000 ;2.34
DC $15D000 ;2.72
DC $190000 ;3.12
DC $7FFFFF ;15.99
;IQUANTAB
DC $800000 ;-16 |I|=0
DC $004000 ;0.031 |I|=1
DC $087000 ;1.05 |I|=2
DC $0D5000 ;1.66 |I|=3
DC $111000 ;2.13 |I|=4
DC $143000 ;2.52 |I|=5
DC $175000 ;2.91 |I|=6
DC $1A9000 ;3.32 |I|=7
;WIBASE
DC $FF4000 ;-0.75 |I|=0
DC $012000 ;1.13 |I|=1
DC $029000 ;2.56 |I|=2
DC $040000 ;4.00 |I|=3
DC $070000 ;7.00 |I|=4
DC $0C6000 ;12.38 |I|=5
DC $163000 ;22.19 |I|=6
DC $462000 ;70.13 |I|=7
;TAB
DC $1E0000
DC $3E0000
DC $5E0000
DC $7E0000
DC $9E0000
DC $BE0000
DC $DE0000
DC $FE0000
;CONST - constants used in FMULT
DC $FFFC00 ;KF1 = trunc mask
DC $7FFC00 ;KF2 = trunc mask
DC $018000 ;KF3 = '48'
DC $7F8000 ;KF4 = trunc mask
DC $00001A ;KF5 = '26'
DC $7FFF00 ;KF6 = trunc mask
;RSHFT
DC $800000
DC $400000 ;>>1 <<23
DC $200000 ;>>2 <<22
DC $100000 ;>>3 <<21
DC $080000 ;>>4 <<20
DC $040000 ;>>5 <<19
DC $020000 ;>>6 <<18
DC $010000 ;>>7 <<17
DC $008000 ;>>8 <<16
DC $004000 ;>>9 <<15
DC $002000 ;>>10 <<14
DC $001000 ;>>11 <<13
DC $000800 ;>>12 <<12
DC $000400 ;>>13 <<11
DC $000200 ;>>14 <<10
DC $000100 ;>>15 <<9
DC $000080 ;>>16 <<8
DC $000040 ;>>17 <<7
DC $000020 ;>>18 <<6
DC $000010 ;>>19 <<5
DC $000008 ;>>20 <<4
DC $000004 ;>>21 <<3
DC $000002 ;>>22 <<2
DC $000001 ;>>23 <<1
;CONST1
DC $FFFE00 ;K1 = trunc mask (ACCUM)
DC $7FFC00 ;K2 = trunc mask (MIX)
DC $7FFE00 ;K3 = trunc mask (MIX)
DC $000080 ;K4 = shift const (EXPAND)
DC $00007F ;K5 = sign mask (EXPAND)
DC $3F8000 ;K6 = trunc mask (LOG)
DC $100000 ;K7 = shift const (LOG)
DC $7FF000 ;K8 = trunc mask (SUBTB & ADDA)
DC $07F000 ;K9 = sign mask (ANTILOG)
DC $00000A ;K10 = '10' (ANTILOG)
DC $7FFE00 ;K11 = trunc mask (ANTILOG)
DC $07C000 ;K12 = trunc mask (TRANS)
DC $000010 ;K13 = shift const (TRANS)
DC $000008 ;K14 = '8' (TRANS)
DC $000005 ;K15 = '5' (TRANS)
DC $7FFE00 ;K16 = trunc mask (TRANS)
DC $008000 ;K17 = +gain (UPB)
DC $FF8000 ;K18 = -gain (UPB)
DC $FFFF00 ;K19 = trunc mask (UPB)
DC $1FFF00 ;K20 = '+1.99' (UPA2)
DC $E00100 ;K21 = '-1.99' (UPA2)
DC $FFFF00 ;K22 = trunc mask (UPA2)
DC $FF4000 ;K23 = -gain (UPA1)
DC $00C000 ;K24 = +gain (UPA1)
DC $FFFF00 ;K25 = trunc mask (UPA1)
DC $040000 ;K26 = shift const (FILTA)
DC $FFF800 ;K27 = trunc mask (FILTA)
DC $FFFE00 ;K28 = trunc mask (FILTB)
DC $FFE000 ;K29 = trunc mask (FILTC)
DC $FFFC00 ;K30 = trunc mask (FILTD)
DC $088000 ;K31 = '1.06' (LIMB)
DC $FFFC00 ;K32 = trunc mask (FILTE)